/*****************************************************************************/
/*!	\file		IEC61850Types.h
 *	\brief		IEC 61580 API definition file
 *	\par		Dalian Yunxing Tech Co., Ltd.
 *
 *				Dalian, China
 *				Phone   : +86 (411) 8825 4852
 *				Email   : yx@yunxing.tech
 */
/*****************************************************************************/

#ifndef IEC61580TYPE_H
#define IEC61580TYPE_H	1

#include "sysctype.h"
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

/*! 对象名称最大长度 */
#define OBJECT_NAME_STRING_LEN 64

/*! 对象引用最大长度 */
#define OBJECT_REFERENCE_STRING_LEN 129

/*! 功能约束字符串的长度 */
#define FC_LEN 2

/*! 控制块引用的最大长度 */
#define CB_REFNAME_SIZE 129

/*! 数据集的引用的最大长度 */
#define DATASET_NAME_SIZE 129
#define CDC_STRING_LEN   8
#define VISIBLE_STRING_129_LEN 129
#define VISIBLE_STRING_255_LEN 255

/*! \brief  数据属性句柄 */
typedef void* DAHANDLE;
/*! \brief  控制块句柄 */
typedef void* CBHANDLE;

#ifndef BITS_TO_BYTES
#define BITS_TO_BYTES(bitSize)		(((bitSize) + 7) / 8)		/*!< Converts size in bits to size in bytes, rounding up to the nearest byte */
#endif

/*!
	\defgroup	ServerCallback			服务端回调函数
	\defgroup	ClientCallback			客户端回调函数
	\defgroup	ServerAndClientCallback	服务端和客户端回调函数
*/

/*! \brief IEC61850_ErrorCode
 * 	\par YX-PIS 协议栈内部使用的错误码，其中以 `IEC61850_ERROR_SCL` 开头的为模型文件内容错误。
 */
typedef enum IEC61850_ErrorCode
{
	IEC61850_ERROR_NONE									= 0,		/*!< 无错误 */
	IEC61850_ERROR_INVALID_PARAMETERS					= -1,		/*!< 参数无效 */
	IEC61850_ERROR_NO_MEMORY							= -2,		/*!< 内存不足 */
	IEC61850_ERROR_SCL_FILE_OPEN_FAILED					= -3,		/*!< 打开模型文件失败 */
	IEC61850_ERROR_SERVICE_FAILED						= -4,		/*!< 服务失败 */
	IEC61850_ERROR_SCL_SYNTAX_ERROR						= -5,		/*!< 模型文件语法错误 */
	IEC61850_ERROR_SCL_IO_ERROR							= -6,		/*!< 模型输入输出错误 */
	IEC61850_ERROR_SCL_NO_IED_CONNECTEDAP				= -7,		/*!< 模型中无IED接入点 */
	IEC61850_ERROR_TYPE_MISMATCH						= -8,		/*!< 类型不匹配 */
	IEC61850_ERROR_LICENCE_INVALID						= -9,		/*!< 许可证无效 */
	IEC61850_ERROR_DATA_ATTRIBUTE_ID_NOT_FOUND			= -10,		/*!< 数据属性ID不存在 */
	IEC61850_ERROR_DATA_ATTRIBUTE_ID_NO_CONNECTION		= -11,		/*!< 数据属性ID对应的数据属性无连接(不可控制) */
	IEC61850_ERROR_SCL_LN_TYPE_NOT_FOUND				= -12,		/*!< 未找到逻辑节点类型定义 */
	IEC61850_ERROR_SCL_DATASET_NOT_FOUND				= -13,		/*!< 未找到数据集定义 */
	IEC61850_ERROR_SCL_GSE_COMM_NOT_FOUND				= -14,		/*!< 未找到GSE控制块对应的通信信息定义 */
	IEC61850_ERROR_SCL_SV_COMM_NOT_FOUND				= -15,		/*!< 未找到采样值控制块对应的通信信息定义 */
	IEC61850_ERROR_SCL_INVALID_MAC_ADDRESS				= -16,		/*!< Mac地址无效 */
	IEC61850_ERROR_GOOSE_INIT_FAILED					= -17,		/*!< GOOSE控制块初始化失败 */
	IEC61850_ERROR_SV_INIT_FAILED						= -18,		/*!< 采样值控制块初始化失败 */
	IEC61850_ERROR_MMS_INIT_FAILED						= -19,		/*!< 服务初始化失败 */
	IEC61850_ERROR_SCL_DATA_TYPE_TEMPLATE_NAME			= -20,		/*!< 数据类型模板名称错误 */
	IEC61850_ERROR_SCL_DATA_TYPE_TEMPLATE_ID			= -21,		/*!< 数据类型模板ID错误 */
	IEC61850_ERROR_SCL_DATASET_NAME						= -22,		/*!< 数据集名称错误 */
	IEC61850_ERROR_SCL_IED_ELEMENT_NAME					= -23,		/*!< IED元素名称错误 */
	IEC61850_ERROR_SCL_COMM_NAME						= -24,		/*!< 通信部分的接入点名称错误 */
	IEC61850_ERROR_INVALID_STATE						= -25,		/*!< 无效状态 */
	IEC61850_ERROR_SCL_DATASET_FCDA_NOT_FOUND			= -26,		/*!< 数据集中没有FCDA元素 */
	IEC61850_ERROR_SCL_DUPLICATE_LD						= -27,		/*!< 逻辑设备重复 */
	IEC61850_ERROR_SCL_LD_NO_NAME						= -28,		/*!< 逻辑设备无名称 */
	IEC61850_ERROR_SCL_LD_NO_LNS						= -29,		/*!< 逻辑设备下无逻辑节点 */
	IEC61850_ERROR_SCL_DUPLICATE_LN						= -30,		/*!< 逻辑节点定义重复 */
	IEC61850_ERROR_SCL_DUPLICATE_DOTYPES				= -31,		/*!< 数据对象类型定义重复 */
	IEC61850_ERROR_SCL_DUPLICATE_DATYPES				= -32,		/*!< 数据属性类型定义重复 */
	IEC61850_ERROR_SCL_DUPLICATE_ENUMTYPE				= -33,		/*!< 枚举类型定义重复 */
	IEC61850_ERROR_SCL_DUPLICATE_LNTYPES				= -34,		/*!< 逻辑节点类型定义重复 */
	IEC61850_ERROR_SCL_DUPLICATE_LNTYPE_DO_NAME			= -35,		/*!< 逻辑节点类型中的数据对象名称重复 */
	IEC61850_ERROR_SCL_LNTYPE_DO_NO_NAME				= -36,		/*!< 逻辑节点内的数据对象无名称 */
	IEC61850_ERROR_SCL_LNTYPE_NO_DOS					= -37,		/*!< 逻辑节点内无数据对象 */
	IEC61850_ERROR_SCL_DUPLICATE_DOTYPE_DA_NAME			= -38,		/*!< 数据对象类型中的数据属性名称重复 */
	IEC61850_ERROR_SCL_DUPLICATE_DOTYPE_SDO_NAME		= -39,		/*!< 数据对象类型中的子数据对象名称重复 */
	IEC61850_ERROR_SCL_DUPLICATE_DATYPE_BDA_NAME		= -40,		/*!< 数据对象类型中的子数据属性名称重复 */
	IEC61850_ERROR_GOOSE_CONTROL_BLOCK_INVALID			= -41,		/*!< GOOSE控制块无效 */
	IEC61850_ERROR_SCL_DUPLICATE_DA_ID					= -42,		/*!< 存在重复的数据属性ID */
	IEC61850_ERROR_CONTROL_NOT_ACTIVE					= -43,		/*!< 控制不可用或非有效控制对象 */
	IEC61850_ERROR_SCL_CONTROL_MODEL_INVALID			= -44,		/*!< 控制模式无效 */
	IEC61850_ERROR_SCL_DAI_WITHOUT_DA_TYPE				= -45,		/*!< 数据属性实例无对应的数据属性类型定义 */
	IEC61850_ERROR_SCL_CLIENT_TOO_FEW_IEDS				= -46,		/*!< 客户端模型中的IED数量过少 */
	IEC61850_ERROR_SERVICE_UNSUPPORTED					= -47,		/*!< 服务不支持 */
	IEC61850_ERROR_SV_CONTROL_BLOCK_INVALID				= -48,		/*!< 采样值控制块无效 */
	IEC61850_ERROR_MMS_COMMS_FAILED						= -49,		/*!< 通信失败 */
	IEC61850_ERROR_MMS_SAP_FAILED						= -50,		/*!< 服务访问点创建失败 */
	IEC61850_ERROR_ARRAY_INDEX_INVALID					= -51,		/*!< 数组元素索引无效 */
	IEC61850_ERROR_OPERATIVE_TEST_CALLBACK_NOT_SET		= -52,		/*!< 运行测试回调未设置 */
	IEC61850_ERROR_OPERATE_CALLBACK_NOT_SET				= -53,		/*!< 操作回调未设置 */
	IEC61850_ERROR_SCL_INVALID_TRIGGER_CONDITION		= -54,		/*!< 触发条件无效 */
	IEC61850_ERROR_SCL_INVALID_REPORT_CONTROL_BLOCK		= -55,		/*!< 报告控制块无效 */
	IEC61850_ERROR_INVALID_IP_ADDRESS					= -56,		/*!< IP地址无效 */
	IEC61850_ERROR_SERVICE_REJECTED						= -57,		/*!< 服务被拒绝 */
	IEC61850_ERROR_EDITION1_OR_EDITION2_FLAG_NOT_SET	= -58,		/*!< 版本标志未设置 */
	IEC61850_ERROR_SCL_MISSING_DO_TYPE_MEMORY			= -59,		/*!< 数据对象类型存储缺失 */
	IEC61850_ERROR_ARRAY_UPDATE_FAILED					= -60,		/*!< 数组更新失败 */
	IEC61850_ERROR_BITLENGTH_MISMATCH					= -61,		/*!< 位长不匹配 */
	IEC61850_ERROR_SELECT_RESPONSE_INVALID				= -62,		/*!< 选择命令响应结果为无效 */
	IEC61850_ERROR_SELECT_MMS_FAILED					= -63,		/*!< 选择命令执行失败 */
	IEC61850_ERROR_GOOSE_DEINITIALIZE_FAILED			= -64,		/*!< GOOSE控制块取消初始化失败 */
	IEC61850_ERROR_MMS_DEINITIALIZE_FAILED				= -65,		/*!< 服务取消初始化失败 */
	IEC61850_ERROR_SAMPLED_VALUES_DEINITIALIZE_FAILED	= -66,		/*!< 采样值控制块取消初始化失败 */
	IEC61850_ERROR_REPORTING_DEINITIALIZE_FAILED		= -67,		/*!< 报告控制块取消初始化失败 */
	IEC61850_ERROR_CONTROLS_DEINITIALIZE_FAILED			= -68,		/*!< 控制服务取消初始化失败 */
	IEC61850_ERROR_CONTROL_BLOCK_DEINITIALIZE_FAILED	= -69,		/*!< 控制块取消初始化失败 */
	IEC61850_ERROR_LOGGING_DEINITIALIZE_FAILED			= -70,		/*!< 日志控制块取消初始化失败 */
	IEC61850_ERROR_FREE_DATA_FAILED						= -71,		/*!< 数据释放失败 */
	IEC61850_ERROR_MMS_OR_CMS_SERVICE_FAILED			= -72,		/*!< 服务启动失败 */
	IEC61850_ERROR_GOOSE_SERVICE_FAILED					= -73,		/*!< GOOSE服务失败 */
	IEC61850_ERROR_SAMPLED_VALUE_SERVICE_FAILED			= -74,		/*!< 采样值服务失败 */
	IEC61850_ERROR_LOGGING_SERVICE_FAILED				= -75,		/*!< 日志服务失败 */
	IEC61850_ERROR_SCL_NO_DAID							= -76,		/*!< 无数据属性ID */
	IEC61850_ERROR_FUNCTION_NOT_SUPPORTED				= -77,		/*!< 功能不支持 */
	IEC61850_ERROR_ENTRYID_SET_ON_URCB_CB				= -78,		/*!< 为非缓存报告控制块设置了EntryID可选域 */
	IEC61850_ERROR_CONTROL_REJECTED						= -79,		/*!< 控制被拒绝 */
	IEC61850_ERROR_SV_GOOSE_CONTROL_BLOCK_CONFLICT		= -80,		/*!< 采样值控制块和GOOSE控制块冲突 */
	IEC61850_ERROR_EXTREF_DAI_NOT_FOUND					= -81,		/*!< 外部链接的数据属性实例不存在 */
	IEC61850_ERROR_MMS_TIMEOUT							= -82,		/*!< 通信超时 */
	IEC61850_ERROR_MMS_FILE_ERROR						= -83,		/*!< 文件服务错误 */
	IEC61850_ERROR_FILE_SYSTEM_ERROR					= -84,		/*!< 文件系统错误 */
	IEC61850_ERROR_GOOSE_SUB_DISABLED					= -85,		/*!< GOOSE订阅被禁用 */
	IEC61850_ERROR_NO_CONTROLS_FOUND					= -86,		/*!< 无可控数据 */
	IEC61850_ERROR_ID_DOES_NOT_MATCH_ACTIVE_CONTROL		= -87,		/*!< 同一控制序列的控制命令的数据属性ID不匹配 */
	IEC61850_ERROR_INVALID_ORIGIN_IDENT_SIZE			= -88,		/*!< 发起者标识大小无效 */
	IEC61850_ERROR_UPDATE_FAILED_VALUE_NOT_SUPPORTED	= -89,		/*!< 因数据值不支持而更新失败 */
	IEC61850_ERROR_SCL_INVALID_FC						= -90,		/*!< 功能约束无效 */
	IEC61850_ERROR_SETTING_GROUP_CONTROL_EMPTY			= -91,		/*!< 定值组内无定值数据 */
	IEC61850_ERROR_SCL_CONTROL_DA_UNSUPORTED			= -92,		/*!< 用于控制命令的数据对象中包含不被支持的数据对象 */
	IEC61850_ERROR_DATASET_MAX_ATTRIBUTES				= -93,		/*!< 数据集中的FCDA数量超出最大限制 */
	IEC61850_ERROR_DATASET_MAX							= -94,		/*!< 数据集数量超出最大限制 */
	IEC61850_ERROR_SCL_MULTIPLE_DAIDS					= -95,		/*!< 同一数据属性有多个数据属性ID */
	IEC61850_ERROR_INFO_START_AT_INVALID				= -96,		/*!< 获取数据点的索引超出数据点总数 */
	IEC61850_ERROR_OBJECT_NON_EXISTENT					= -97,		/*!< 对象不存在 */
	IEC61850_ERROR_SCL_DUPLICATE_GOCB_ID				= -98,		/*!< GOOSE控制块的控制块ID重复 */
	IEC61850_ERROR_SCL_DUPLICATE_RPTCB_ID				= -99,		/*!< 报告控制块的控制块ID重复 */
	IEC61850_ERROR_SERVERAT_AP_NOT_FOUND				= -100,		/*!< ServerAt接入点不存在 */
	IEC61850_ERROR_SERVERAT_SAME_HAVE_GOOSE_SV_AP		= -101,		/*!< 同一个AP存在多个服务器,且该AP包含goose或sv */
} IEC61850_ErrorCode;

/*! 控制发起者标识最大长度 */
#define CONTROL_ORIGIN_IDENT_SIZE 64

#define CONTROL_TIME_SIZE 8

/*! 控制请求的发起者类别。orCat = OriginatorCatagory
与 IEC61850-7-3-2010（DL/T 860.73-2013）的 6.8 章节的 "发起者 Originator" 内容相对应 */
typedef enum eOriginatorCat
{
	ORCAT_NOT_SUPPORTED			= 0, /*!< orCat不被支持 */
	ORCAT_BAY_CONTROL			= 1, /*!< 间隔层 */
	ORCAT_STATION_CONTROL		= 2, /*!< 变电站层 */
	ORCAT_REMOTE_CONTROL		= 3, /*!< 变电站外<br>例如 CC（ControlCentre 控制中心）、NCC（NetworkCC 网络控制中心）的远程控制 */
	ORCAT_AUTOMATIC_BAY			= 4, /*!< 间隔层自动 */
	ORCAT_AUTOMATIC_STATION		= 5, /*!< 变电站层自动 */
	ORCAT_AUTOMATIC_REMOTE		= 6, /*!< 变电站外自动  */
	ORCAT_MAINTENANCE			= 7, /*!< 维护/服务工具 */
	ORCAT_PROCESS				= 8, /*!< 过程层<br>无视控制行为而出现的状态变位（如断路器外部跳闸或内部故障） */
} eOriginatorCat;

/*!	\brief	抽象通信服务接口类（ACSIClass）
对应的是 IEC61850-7-2:2010（DL/T 860.72-2013）的第 10.2.2.2.2 章节中定义的 "ACSIClass 抽象通信服务接口类" */
typedef enum IEC61850_ACSIClass
{
	ACSI_CLASS_RESERVED = 0,		/*!< 保留值（Reserved）。<b>禁止使用</b> */
	ACSI_CLASS_DATA_OBJECT = 1,		/*!< 数据对象（Data object） */
	ACSI_CLASS_DATA_SET = 2,		/*!< 数据集（DATA-SET） */
	ACSI_CLASS_BRCB = 3,			/*!< 缓存报告控制块（BRCB） */
	ACSI_CLASS_URCB = 4,			/*!< 非缓存报告控制块（URCB） */
	ACSI_CLASS_LCB = 5,				/*!< 日志控制块（LCB） */
	ACSI_CLASS_LOG = 6,				/*!< 日志（LOG） */
	ACSI_CLASS_SGCB = 7,			/*!< 定值组控制块（SGCB） */
	ACSI_CLASS_GoCB = 8,			/*!< GOOSE 控制块（GoCB） */
	ACSI_CLASS_MSVCB = 10,			/*!< 多播采样值控制块（MSVCB） */
} IEC61850_ACSIClass;

/*!	\brief	数据属性ID（DAID）<br>
虽然 DAID 的 5 个域的数据类型都是 unsigned int，但建议每个域的数值都设置在 0~65535 之间 */
typedef struct IEC61850_DataAttributeID
{
	unsigned int field1;	/*!< 数据属性ID 的第一个数据域（Field1）的值 */
	unsigned int field2;	/*!< 数据属性ID 的第二个数据域（Field2）的值 */
	unsigned int field3;	/*!< 数据属性ID 的第三个数据域（Field3）的值 */
	unsigned int field4;	/*!< 数据属性ID 的第四个数据域（Field4）的值 */
	unsigned int field5;	/*!< 数据属性ID 的第五个数据域（Field5）的值 */
} IEC61850_DataAttributeID;

/*! \brief	控制块类别<br>
 *	\details
 *	该枚举值在 `struct IEC61850_ControlBlockID` 中使用，用于标记带有数据上报性质的控制块的类别。<br>
 *	属于 YX-PIS 协议栈私有属性 "控制块ID（Control Block ID）" 的一部分。
 */
typedef enum eControlBlockType
{
	CONTROLBLOCK_GOOSE,		/*!< GOOSE 控制块 */
	CONTROLBLOCK_REPORT,	/*!< 报告控制块 */
	CONTROLBLOCK_LOG,		/*!< 日志控制块 */
	CONTROLBLOCK_SV,		/*!< 采样值控制块 */
} eControlBlockType;

/*!	\brief	控制块ID（Control Block ID），简称为 CBID。
 *	\details
 *	控制块ID 是 YX-PIS 协议栈特有的内容。用于映射模型中的控制块，便于以控制块整体为单位对控制块关联的数据做处理。
 *	控制块ID 实际由 4 个无符号整型的数据域（Field1~Field4）、以及一个控制块的索引号构成，四个数据域的值来源于模型文件中给控制块分配的 控制块ID 定义。（在建模时额外配置）。
 *	虽然 控制块ID 的 4 个域的数据类型都是 unsigned int，但建议每个域的数值都设置在 0~65535 之间。
 */
typedef struct IEC61850_ControlBlockID
{
	eControlBlockType	controlBlockType;	/*!< 控制块的类别 */
	U32 	field1;		/*!< 控制块ID 的第一个数据域（Field1）的值 */
	U32 	field2;		/*!< 控制块ID 的第二个数据域（Field2）的值 */
	U32 	field3;		/*!< 控制块ID 的第三个数据域（Field3）的值 */
	U32 	field4;		/*!< 控制块ID 的第四个数据域（Field4）的值 */
	U32 	index;		/*!< 控制块的索引值。<br>由控制块在模型中的定义顺序决定。<br>值从 0 开始，按顺序依次递增 1。 */
} IEC61850_ControlBlockID;

/*!	\brief	控制块句柄信息  */
typedef struct IEC61850_CBHandleInfo
{
	eControlBlockType	controlBlockType;	/*!< 控制块的类别 */
	CBHANDLE			handle;				/*!< 控制块的句柄 */
	U32					index;				/*!< 控制块实例的编号。<br>对于报告控制块，0 代表所有实例，1~99 依次代表报告控制块的实例 01~99<br>对于GOOSE控制块，值应固定为 0 */
} IEC61850_CBHandleInfo;

/*!	IEC61850 的数据类型<br>
 * 对应类型的解释可以参照 IEC61850-7-2:2010（DL/T 860.72-2013）的 6.1.1 章节。<br>
 */
typedef enum IEC61850_DataType
{
	IEC61850_DATATYPE_ERROR = 0,			/*!< #eServiceError 服务差错 */
	IEC61850_DATATYPE_BOOLEAN = 1,			/*!< BOOLEAN 布尔 */
	IEC61850_DATATYPE_INT8 = 2,				/*!< INT8 有符号整型 */
	IEC61850_DATATYPE_INT16 = 3,			/*!< INT16 有符号整型 */
	IEC61850_DATATYPE_INT32 = 4,			/*!< INT32 有符号整型 */
	IEC61850_DATATYPE_INT64 = 5,			/*!< INT64 有符号整型 */
	IEC61850_DATATYPE_INT8U = 6,			/*!< INT8U 无符号整型 */
	IEC61850_DATATYPE_INT16U = 7,			/*!< INT16U 无符号整型 */
	IEC61850_DATATYPE_INT32U = 8,			/*!< INT32U 无符号整型 */
	IEC61850_DATATYPE_FLOAT32 = 9,			/*!< FLOAT32 单精度浮点型 */
	IEC61850_DATATYPE_FLOAT64 = 10,			/*!< FLOAT64 双精度浮点型 */
	IEC61850_DATATYPE_ENUMERATED = 11,		/*!< ENUMERATED 枚举 */
	IEC61850_DATATYPE_CODED_ENUM = 12,		/*!< CODED ENUM 固定枚举(不可扩展) */
	IEC61850_DATATYPE_OCTET_STRING = 13,	/*!< OCTET STRING 八位组串 */
	IEC61850_DATATYPE_VISIBLE_STRING = 14,	/*!< VisibleString 可视字符串 */
	IEC61850_DATATYPE_UNICODE_STRING = 15,	/*!< UNICODE STRING Unicode字符串 */
	IEC61850_DATATYPE_TIMESTAMP = 16,		/*!< TimeStamp 时间戳 */
	IEC61850_DATATYPE_QUALITY = 17,			/*!< Quality 品质 #IEC61850_QualityFlag */
	IEC61850_DATATYPE_ARRAY = 18,			/*!< Array 数组 */
	IEC61850_DATATYPE_STRUCTURE = 19,		/*!< Structure 结构体 */

	IEC61850_DATATYPE_BITSTRING = 100,  /*!< bit-string (内部使用) */
} IEC61850_DataType;

/*!	\brief	数据值。包含数据值对应的数据类型。用于保存某个数据属性以及其下所有层级的完整数据信息 */
typedef struct IEC61850_DataAttributeData
{
	unsigned char type;		/*!< 数据类型。<br>取值为 `enum IEC61850_DataType` 类型的枚举值之一。<br>若数据类型为数组或者结构体，则每个数组元素或结构体成员，都将是一个单独的 `IEC61850_DataAttributeData` 类型的数据。 */
	int arrayIndex;			/*!< 数组元素索引。<br>若当前数据属性为数组类型数据中的某个元素时，该值有效，值为当前数据对应的数组元素索引；否则该值无意义，值为 0。 */
	unsigned int bitLength;	/*!< 数据长度信息。其值的意义，因数据类型而异。<br>若数据类型是数组，则该值代表数组元素数量；<br>若数据类型是结构体，则代表结构体成员的数量；<br>若数据类型既不是数组也不是结构体，则该值代表对应数据类型所占的实际位（bit）数。（例如，INT32 类型数据大小为 32 bit，则该值对应为 32。） */
	void* pvData;			/*!< 数据值的指针。<br>该指针指向数据值所在的内存空间地址。<br>若数据类型为数组数据，则该指针指向一个包含 `bitLength` 个 `IEC61850_DataAttributeData` 类型的数组元素的数组的首地址；<br>若数据类型为结构体，则该指针指向一个由 `bitLength` 个连续的 `IEC61850_DataAttributeData` 类型的结构体成员数据所构成的内存空间的首地址；<br>若数据类型既不是数组，也不是结构体，则可以按照对应的数据类型对该地址解引用来获取数据值。 */
} IEC61850_DataAttributeData;

#define IEC61850_ERROR_STRING_SIZE	256	/*!< Length of strings in #IEC61850_ErrorParameters */

/*!	\brief	错误消息信息<br>
用于 `IEC61850_ErrorCallback` 回调函数的错误消息参数解析。<br>
该数据用于解析内容为 最新应用错误（LastApplError）的 MMS 信息报告（Information Report）。<br>
关于 最新应用错误（LastApplError）的说明，请参照 IEC61850-7-2-2010（DL/T 860.81-2013）的 20.11 章节。 */
typedef struct IEC61850_ErrorParameters
{
	char domainName[IEC61850_ERROR_STRING_SIZE];	/*!< 错误对象的域名。<br>与 `itemName` 合在一起，为数据对象的 MMS 格式的 FCDA 引用。例如 "LDName/CSWI0\$CO\$Pos\$Oper"。`domainName` 是 "LDName"。 */
	char itemName[IEC61850_ERROR_STRING_SIZE];		/*!< 错误对象的条目名。<br>与 `domainName` 合在一起，为数据对象的 MMS 格式的 FCDA 引用。例如 "LDName/CSWI0\$CO\$Pos\$Oper"。`itemName` 是 "CSWI0\$CO\$Pos\$Oper"。 */
	char reference[OBJECT_REFERENCE_STRING_LEN + 1];/*!< 错误对象的引用 */
	char errorType[IEC61850_ERROR_STRING_SIZE];		/*!< 错误类型字符串。<br>是 `iErrorType` 值所对应的字符串解释。 */
	U8 iErrorType;									/*!< 错误类型数值。<br>对应的是 LastApplError 的错误（Error）。<br>0：没有错误（No Error）<br>1：未知（Unknown）<br>2：超时测试不灵（Timeout Test Not OK）<br>3：操作者测试不灵（Operator Test Not OK） */
	char errorCause[IEC61850_ERROR_STRING_SIZE];	/*!< 错误原因字符串。<br>是 `iErrorCause` 值所对应的字符串解释。 */
	U8 iErrorCause;									/*!< 错误原因数值。<br>对应的是 LastApplError 的额外原因（AddCause）。 */
} IEC61850_ErrorParameters;

/*!	客户端与服务端的关联状态 */
typedef enum IEC61850_ServerStatusVal
{
	SERVER_STATUS_UNKNOWN		= 0,	/*!< 未知（初始状态） */
	SERVER_STATUS_CONNECTED		= 1,	/*!< 已连接，通信中 */
	SERVER_STATUS_DISCONNECTED	= 2,	/*!< 连接断开 */
	SERVER_STATUS_CONNECTING	= 3,	/*!< 连接中 */
	SERVER_STATUS_DISCONNECTING	= 4,	/*!< 断开连接中 */
} IEC61850_ServerStatusVal;

/*!	\brief	YX-PIS 协议栈内更新 Boolean 类型数据时使用的 Boolean 类型的 bit 长度。<br>
 *	区别于 IEC61850 传输 Boolean 类型数据时，对 Boolean 类型数据的实际编码长度（1 bit）。	
 */
#define IEC61850_BOOLEAN_BITSIZE	8

/*!	\brief	时间戳类型数据的 bit 长度
 *	\see IEC61850_TimeStamp
 */
#define IEC61850_TIMESTAMP_BITSIZE	64

/*!	\brief	IEC61850 时间戳
	\details
	\b 秒的整数：
	其值为 UTC 时间的秒级时间戳。

	\b 秒的小数：
	秒的小数是一个长度为 24 的 bit 位串（BIT STRING）数据，共占三个字节。<br>
	IEC61850 规范中，秒的小数的值，是使用这个位串的每个 bit 位，按以下方法计算得到的。<br>
	计算公式为：\f${\sum_{n=0}^{23} (b_n * 2^{-(n+1)})}\f$<br>

	其中，\f${n}\f$ 为每个 bit 位的序号。24 个 bit 位中，最高位的序号为 0，最低位的序号为 23，<br>
	\f${b_n}\f$ 为每个 bit 位的值：0 或者 1，<br>
	每个 bit 位所代表的数值为：\f${b_n * 2^{-(n+1)}}\f$，<br>
	秒的小数的值，为所有 24 个 bit 位所代表的数值的总和。即，每个被置为 1 的 bit 位所代表的数值的总和。<br>

	举个例子，假设秒的小数的三个字节的位串值（二进制）为： 10001000 01000100 00000010<br>
	该值中，序号为 0、4、9、13、22 的 bit 位被置为了 1，<br>
	因此秒的小数的值为 \f$2^{-1}\f$ + \f$2^{-5}\f$ + \f$2^{-10}\f$ + \f$2^{-14}\f$ + \f$2^{-23}\f$ = 0.5 + 0.03125 + 0.000976562 + 0.000061035 + 0.000000119 = 0.532287716

	\b 时间品质：
	时间品质是一个长度为 8 的 bit 位串（BIT STRING）数据，占一个字节。<br>
	对于位串数据来说，最高位为位 0，因此其最低位则为位 7。<br>
	这些位所代表的含义如下：

	| 位   | 含义                                    |
	| ---- | --------------------------------------- |
	| 0    | 闰秒已知（LeapSecondsKnown）            |
	| 1    | 时钟故障（ClockFailure）                |
	| 2    | 时钟未同步（ClockNotSynchronized）      |
	| 3~7  | "秒的小数" 的时间精确度（TimeAccuracy） |

	"秒的小数" 的时间精确度：

	| 时间品质 3~7 位的值 | 含义                             |
	| ------------------- | -------------------------------- |
	| 00000               | 0 位精度（相当于秒的小数值为 0） |
	| 00001               | 1 位精度（0.5 秒）               |
	| 00010               | 2 位精度（0.25 秒）              |
	| 00011               | 3 位精度（0.125 秒）             |
	| 00100~11000         | 数值所对应的整数位精度           |
	| 11001~11110         | 非法                             |
	| 11111               | 未规定                           |

	取时间品质的第 3~7 五个 bit 位的时间精确度的十进制整数值，记为 n，其数值代表的时间精确度则为 \f${2^{-n}}\f$ 秒。<br>
	0 ≤ n ≤ 24 时，时间精确度为对应的有效值；n = 31 代表时间精确度未规定；<br>
	其他的 n 值（25~30）因为其代表的时间精确度，不属于常规使用的时间精确度（超出了纳秒级范围），被视为非法值。<br>
	具体如下表：（关于时间性能等级，可参照 IEC61850-5-2013（DL/T 860.5））

	| n 值  | 时间精确度         | 时间性能等级    |
	| ----- | ------------------ | --------------- |
	| 0     | 1s                 | TL（\>10000μs） |
	| 1     | 0.5s               | TL（\>10000μs） |
	| 2     | 0.25s              | TL（\>10000μs） |
	| 3     | 0.125s             | TL（\>10000μs） |
	| 4     | 62.5ms             | TL（\>10000μs） |
	| 5     | 31.25ms            | TL（\>10000μs） |
	| 6     | 15.625ms           | TL（\>10000μs） |
	| 7     | 7.8125ms           | T0（10000μs）   |
	| 8     | 3.90625ms          | T0（10000μs）   |
	| 9     | 1.953125ms         | T0（10000μs）   |
	| 10    | 976.562μs（≈ 1ms） | T1（1000μs）    |
	| 11    | 488.281μs          | T1（1000μs）    |
	| 12    | 244.141μs          | T1（1000μs）    |
	| 13    | 122.070μs          | T1（1000μs）    |
	| 14    | 61.035μs           | T2（100μs）     |
	| 15    | 30.518μs           | T2（100μs）     |
	| 16    | 15.259μs           | T3（25μs）      |
	| 17    | 7.629μs            | T3（25μs）      |
	| 18    | 3.815μs            | T4（4μs）       |
	| 19    | 1.907μs            | T4（4μs）       |
	| 20    | 954ns              | T5（1μs）       |
	| 21    | 477ns              | T5（1μs）       |
	| 22    | 238ns              | T5（1μs）       |
	| 23    | 119ns              | T5（1μs）       |
	| 24    | 60ns               | T5（1μs）       |
	| 25~30 | 非法               | -               |
	| 31    | 未规定             | -               |
*/
typedef struct IEC61850_TimeStamp
{
	U32	seconds;			/*!< 秒的整数 */
	U32	fractionsOfSecond;	/*!< 秒的小数 + 时间品质。<br>最低一个字节（8 个 bit 位）用来表示时间品质，其余的三个字节（24 个 bit 位）用来表示秒的小数 */
} IEC61850_TimeStamp;

/*!	\brief	服务端的状态信息 */
typedef struct IEC61850_ServerStatus
{
	char* ipAddress;						/*!< IP 地址 */
	char* iedName;							/*!< IED 名称 */
	S32 OSErrorCode;						/*!< 系统错误码。用于保存系统级的错误信息 */
	IEC61850_ServerStatusVal isConnected;	/*!< 客户端与该服务端 IED 的连接状态 */
} IEC61850_ServerStatus;

/*!	\brief	服务端的状态信息列表 */
typedef struct IEC61850_ServerStatusArray
{
	IEC61850_ServerStatus* serverStatusArray;	/*!< 服务端的状态信息列表。<br>信息源自客户端模型文件中所引用的服务端 IED 模型。<br>内容为 `IEC61850_ServerStatus` 的数组，数组元素数量由 `ServerStatusArraySize` 指定 */
	int serverStatusArraySize;					/*!< `serverStatusArray` 中 `IEC61850_ServerStatus` 元素的数量 */
} IEC61850_ServerStatusArray;

/*!  IEC61850 Quality flags. (see IEC 61850-8-1:2004 section 8.2)  */
typedef enum IEC61850_TimeQualityFlag
{
	IEC61850_TIMEQUALITY_LEAP_SECOND_KNOWN		= 0x0000000080,	/*!< Leap second known flag */
	IEC61850_TIMEQUALITY_CLOCK_FAILURE			= 0x0000000040,	/*!< Clock failure flag */
	IEC61850_TIMEQUALITY_CLOCK_NOT_SYNCHRONIZED	= 0x0000000020,	/*!< Clock not synchronised flag */
	IEC61850_TIMEQUALITY_0_BIT_OF_ACCURACY		= 0x0000000000,	/*!< 0 bit accuracy flag */
	IEC61850_TIMEQUALITY_1_BIT_OF_ACCURACY		= 0x0000000001,	/*!< 1 bit accuracy flag */
	IEC61850_TIMEQUALITY_24_BIT_OF_ACCURACY		= 0x0000000018,	/*!< 24 bit accuracy flag */
	IEC61850_TIMEQUALITY_ACCURACY_UNSPECIFIED	= 0x000000001F,	/*!< Accuracy unspecified flag */
} IEC61850_TimeQualityFlag;

/*!	\brief	品质（quality）类型数据的 bit 长度 */
#define IEC61850_QUALITY_BITSIZE	13

/*!	\brief	品质（quality）作为长度固定为 13 bit 的位串数据，在 YX-PIS 协议栈中，使用一个 U16（INT16U） 的数据来处理。<br>
品质数据的定义，可以参照 IEC61850-7-3-2010（DL/T 860.73-2013）的 6.2 章节。<br>
协议栈内通过 INT16U 数据来处理品质数据时，使用 `enum IEC61850_QualityFlag`。( #IEC61850_QualityFlag) */
typedef U16 tIEC61850Quality;

/*!	\typedef	IEC61850_QualityFlag
	\brief	品质（Quality）数据位标记
	\details
	用 INT16U 类型的数据来设置或解析 13 bit 的品质（quality）位串数据的枚举值定义。<br>
	用于在 `IEC61850_DataAttributeData` 中设置或解析品质数据。<br>
	其每个枚举值，代表品质数据中对应一个到两个 bit 位的意义。涉及多个品质 bit 位时，互为 或运算（`|`）的关系。<br>
	<br>
	INT16U 作为（网络大端序）位串数据的前 13 bit，代表实际的品质数据值。<br>
	其中，0~1 的前两个 bit 位整体代表品质的有效性（validity），这两个 bit 位是品质的主要数据值；<br>
	2~9 的每个 bit 位，各代表一种详细品质（detailQual）属性；<br>
	第 10 个 bit 位代表品质的数据源（source）属性，<br>
	由于该 bit 位代表数据源是 `process` 时的 bit 值为 0，0 与任意值做或（`|`）运算无必要，因此仅定义了该 bit 代表数据源是 `substituted` （bit 值为 1）时的枚举值；<br>
	第 11、12 两个 bit 位依次代表品质的 测试（test） 和 操作员闭锁（operatorBlocked）属性。<br>
	<br>
	由于 INT16U 的数据长度为 2 字节，因此值会涉及到大小端序的差异，<br>
	定义中将区分小端序和大端序的枚举值，使用时，请使用枚举名称。<br>
	在客户端服务端通信交互的数据包中，该数据值将被转换为网络大端序的位串来处理。<br>
	<br>
	关于品质数据的描述，可参照 IEC 61850-7-3:2010（DL/T 860.73-2013）的 6.2 章节。<br>
	关于品质数据的 MMS 映射，可参照 IEC 61850-8-1:2011 的 8.2 章节。
*/
typedef enum IEC61850_QualityFlag
{
#ifdef __BIGENDIAN__	// big-endian
	IEC61850_QUALITY_GOOD				= 0x0000,	/*!< Good */
	IEC61850_QUALITY_INVALID			= 0x4000,	/*!< Invalid */
	IEC61850_QUALITY_RESERVED			= 0x8000,	/*!< Reserved */
	IEC61850_QUALITY_QUESTIONABLE		= 0xC000,	/*!< Questionable */
	IEC61850_QUALITY_OVERFLOW			= 0x2000,	/*!< Overflow */
	IEC61850_QUALITY_OUTOFRANGE			= 0x1000,	/*!< Out of Range */
	IEC61850_QUALITY_BADREFERENCE		= 0x0800,	/*!< Bad Reference */
	IEC61850_QUALITY_OSCILLATORY		= 0x0400,	/*!< Oscillatory */
	IEC61850_QUALITY_FAILURE			= 0x0200,	/*!< Failure */
	IEC61850_QUALITY_OLDDATA			= 0x0100,	/*!< Old Data */
	IEC61850_QUALITY_INCONSISTENT		= 0x0080,	/*!< Inconsistent */
	IEC61850_QUALITY_INACCURATE			= 0x0040,	/*!< Inaccurate */
	IEC61850_QUALITY_SUBSTITUTED		= 0x0020,	/*!< Substituted if not set then Source is from the process */
	IEC61850_QUALITY_TEST				= 0x0010,	/*!< Test */
	IEC61850_QUALITY_OPERATOR_BLOCKED	= 0x0008,	/*!< Blocked by Operator */
	IEC61850_QUALITY_SV_DER				= 0x0004,	/*!< Derived Quality for Sampled Values ONLY, Der field is an identifier of the derived current sampled value. Der should be set when the value is calculated and not a measurement */
#else	// little-endian
	IEC61850_QUALITY_GOOD				= 0x0000,	/*!< bit 0~1, validity   / Good */
	IEC61850_QUALITY_INVALID			= 0x0040,	/*!< bit 0~1, validity   / Invalid */
	IEC61850_QUALITY_RESERVED			= 0x0080,	/*!< bit 0~1, validity   / Reserved */
	IEC61850_QUALITY_QUESTIONABLE		= 0x00C0,	/*!< bit 0~1, validity   / Questionable */
	IEC61850_QUALITY_OVERFLOW			= 0x0020,	/*!< bit 2,   detailQual / Overflow */
	IEC61850_QUALITY_OUTOFRANGE			= 0x0010,	/*!< bit 3,   detailQual / Out of Range */
	IEC61850_QUALITY_BADREFERENCE		= 0x0008,	/*!< bit 4,   detailQual / Bad Reference */
	IEC61850_QUALITY_OSCILLATORY		= 0x0004,	/*!< bit 5,   detailQual / Oscillatory */
	IEC61850_QUALITY_FAILURE			= 0x0002,	/*!< bit 6,   detailQual / Failure */
	IEC61850_QUALITY_OLDDATA			= 0x0001,	/*!< bit 7,   detailQual / Old Data */
#if defined (__PARADIGM__) /* Need to typecast to int on BECK RTOS on 16bit SC1x3 CPU due to enums being stored in 16bit signed integer */
	IEC61850_QUALITY_INCONSISTENT		= (int)0x8000,	/*!< bit 8,   detailQual / Inconsistent */
#else
	IEC61850_QUALITY_INCONSISTENT		= 0x8000,	/*!< bit 8,   detailQual / Inconsistent */
#endif
	IEC61850_QUALITY_INACCURATE			= 0x4000,	/*!< bit 9,   detailQual / Inaccurate */
	IEC61850_QUALITY_SUBSTITUTED		= 0x2000,	/*!< bit 10,  source     / Substituted if not set then Source is from the process */
	IEC61850_QUALITY_TEST				= 0x1000,	/*!< bit 11,  test       / Test */
	IEC61850_QUALITY_OPERATOR_BLOCKED	= 0x0800,	/*!< bit 12,  operatorBlocked / Blocked by Operator */
	IEC61850_QUALITY_SV_DER				= 0x0400,	/*!< Derived Quality for Sampled Values ONLY, Der field is an identifier of the derived current sampled value. Der should be set when the value is calculated and not a measurement - defined in 9-2LE*/
#endif	// (#ifdef __BIGENDIAN__)
} IEC61850_QualityFlag;

/*!	\brief	YX-PIS 协议栈内用于截取品质（quality）数据中的有效性（validity）部分的值（good \| invalid \| reserved \| questionable）的掩码。<br>
 *	用于结合 `enum IEC61850_QualityFlag` 使用，以从用 INT16U 数据类型保存的品质数据中，<br>
 *	提取出主要代表数据品质的 validity 部分的值，过滤掉品质数据中 detailQual、test、operatorBlocked 的数据部分。
 */
#ifdef __BIGENDIAN__
	#define IEC61850_QUALITY_BITMASK_VALIDITY 0xC000	// big-endian
#else
	#define IEC61850_QUALITY_BITMASK_VALIDITY 0x00C0	// little-endian
#endif	// of (#ifndef __BIGENDIAN__)

/*! \brief  用于设置或解析 RCB 选项域(OptFlds) 位串数据的枚举值
	\details
	用 INT16U 类型的数据来设置或解析 10 bit 的报告控制块可选域（OptFlds）位串数据的枚举值定义。<br>
	用于在 `SetBRCBValues`、`SetURCBValues` 中设置报告控制块的可选域，以及在 `BRCBValues`、`URCBValues` 中解析报告控制块的可选域。<br>
	其每个枚举值，都代表一个对应 bit 位的意义。涉及多个可选域 bit 位时，互为 或运算（`|`）的关系。<br>
	<br>
	INT16U 作为（网络大端序）位串数据的前 10 bit，代表实际报告控制块可选域的数据值。<br>
	由于 INT16U 的数据长度为 2 字节，因此值会涉及到大小端序的差异，<br>
	定义中将区分小端序和大端序的枚举值，使用时，请使用枚举名称。<br>
	在客户端服务端通信交互的数据包中，该数据值将被转换为网络大端序的位串来处理。<br>
*/
typedef enum IEC61850_ReportOption
{
#ifdef __BIGENDIAN__	// big-endian
	IEC61850_REPORT_OPTIONAL_RESERVED = 0x8000,				/*!< 保留 */
	IEC61850_REPORT_OPTIONAL_SEQUENCE_NUMBER = 0x4000,		/*!< 序列号 */
	IEC61850_REPORT_OPTIONAL_REPORT_TIME_STAMP = 0x2000,	/*!< 报告时标 */
	IEC61850_REPORT_OPTIONAL_REASON_FOR_INCLUSION = 0x1000,	/*!< 包含原因 */
	IEC61850_REPORT_OPTIONAL_DATA_SET_NAME = 0x0800,		/*!< 数据集名称 */
	IEC61850_REPORT_OPTIONAL_DATA_REFERENCE = 0x0400,		/*!< 数据引用 */
	IEC61850_REPORT_OPTIONAL_BUFFER_OVERFLOW = 0x0200,		/*!< 缓存区溢出 */
	IEC61850_REPORT_OPTIONAL_ENTRY_ID = 0x0100,				/*!< 条目标识 */
	IEC61850_REPORT_OPTIONAL_CONF_REVISION = 0x0080,		/*!< 配置版本 */
	IEC61850_REPORT_OPTIONAL_SEGMENTATION = 0x0040,			/*!< 分段 */
#else	// little-endian
	IEC61850_REPORT_OPTIONAL_RESERVED = 0x0080,				/*!< 保留（reserved）。<br>该 bit 位应始终为 0，禁止设置。  */
	IEC61850_REPORT_OPTIONAL_SEQUENCE_NUMBER = 0x0040,		/*!< 时序号（sequence-number）  */
	IEC61850_REPORT_OPTIONAL_REPORT_TIME_STAMP = 0x0020,	/*!< 时间戳（report-time-stamp）  */
	IEC61850_REPORT_OPTIONAL_REASON_FOR_INCLUSION = 0x0010,	/*!< 原因码（reason-for-inclusion） */
	IEC61850_REPORT_OPTIONAL_DATA_SET_NAME = 0x0008,		/*!< 数据集名称（data-set-name） */
	IEC61850_REPORT_OPTIONAL_DATA_REFERENCE = 0x0004,		/*!< 数据引用（data-reference） */
	IEC61850_REPORT_OPTIONAL_BUFFER_OVERFLOW = 0x0002,		/*!< 缓存溢出标记（buffer-overflow） */
	IEC61850_REPORT_OPTIONAL_ENTRY_ID = 0x0001,				/*!< 条目ID（entryID）  */
	IEC61850_REPORT_OPTIONAL_CONF_REVISION = 0x8000,		/*!< 配置版本号（conf-revision）  */
	IEC61850_REPORT_OPTIONAL_SEGMENTATION = 0x4000,			/*!< 分段（segmentation）。<br>该 bit 位应始终为 0，禁止设置。 */
#endif	// (#ifdef __BIGENDIAN__)
} IEC61850_ReportOption;

typedef enum IEC61850TriggerOption
{
	IEC61850_TRIGGER_OPTIONS_RESERVED			= 0x80,	/*!< 保留 (reserved) */
	IEC61850_TRIGGER_OPTIONS_DATA_CHANGE		= 0x40,	/*!< 数据改变 (dchg) */
	IEC61850_TRIGGER_OPTIONS_QUATLITY_CHANGE	= 0x20,	/*!< 品质改变 (qchg) */
	IEC61850_TRIGGER_OPTIONS_DATA_UPDATE		= 0x10,	/*!< 数据更新 (dupd) */
	IEC61850_TRIGGER_OPTIONS_INTEGRITY			= 0x08,	/*!< 完整性 (integrity) */
	IEC61850_TRIGGER_OPTIONS_GI					= 0x04,	/*!< 总召唤 (general-interrogation) */
} IEC61850TriggerOption;

/*!	\brief	YX-PIS 协议栈内更新 ENUMERATED 类型数据时使用的 ENUMERATED 类型的 bit 长度 */
#define IEC61850_ENUM_BITSIZE	8

/*!	\brief	IEC61850 Enumerated data type. (as specified in IEC61850_DATATYPE_ENUMERATED or IEC61850_DATATYPE_CODED_ENUM) */
typedef U8 tIEC61850Enum;

/*!	\brief	双点位置（Dbpos）类型在 IEC61850 中定义为 CODED ENUM 类型，即，实际是一个 2 bit 长度的位串数据。（同 `enum eDbPosValues` ）。
在协议栈中，双点位置的位串数据值，通常在 `IEC61850_DataAttributeData` 中，通过 INT8U 的数据类型来保存和解析。（同 `enum IEC61850DbPosValue`）。 
 */
#define IEC61850_DATATYPE_DBPOS  IEC61850_DATATYPE_INT8U

/*!	\brief	YX-PIS 协议栈内使用 INT8U 数据来处理双点位置（Dbpos）数据时的数据类型 bit 长度。<br>
该值用于在协议栈内通过 `IEC61850_DataAttributeData` 来更新双点位置数据时，标记数据的类型为双点位置（Dbpos）类型。<br>
协议栈会依据此类型，来将 `IEC61850_DataAttributeData` 中通过 INT8U 类型保存的双点位置数据，按照双点位置数据的实际长度（2 bit 的位串）来处理。
 (#IEC61850_DATATYPE_DBPOS) 	 */
#define IEC61850_DBPOS_BITSIZE	8

/*!	\brief	双点位置（Dbpos）。
	\details
	双点位置是一个 2bit 的位串数据。<br>
	该枚举值与 IEC61850 双点位置数据的定义一致。<br>
	<br>
	双点位置类型是 DPS、DPC 公共数据类的数据对象的状态值（stVal）的数据类型。<br>
	参照 IEC61850-7-3 中对 DPS、DPC 这两个公共数据类的定义，双点位置类型被定义为 CODED ENUM，实际上是一个 2 bit 长度的位串数据。<br>
	其取值为：`intermediate-state`、`off`、`on`、`bad-state`，其依次对应值： 0、1、2、3，即二进制的 `00`、`01`、`10`、`11`。<br>
	<br>
	在协议栈内，服务端要更新双点位置类型的数据时，应使用与双点位置定义相同的 `enum #eDbPosValues`。<br>
	特殊的，双点位置类型的数据更新触发客户端的数据更新回调时，数据更新回调函数中传入的双点位置数据，<br>
	是通过 INT8U 数据类型来保存的双点数据的位串，应使用 `enum IEC61850DbPosValue` 来解析，然后转换为相应的 `enum eDbPosValues`。 
*/
typedef enum eDbPosValues
{
	DBPOS_INTERMEDIATE	= 0,	/*!< 中间状态（intermediate-state）  */
	DBPOS_OFF = 1,				/*!< 分闸（off） */
	DBPOS_ON = 2,				/*!< 合闸（on） */
	DBPOS_BAD = 3,				/*!< 故障状态（bad-state）  */
} eDbPosValues;

/*!	双点位置（Dbpos）（2 bit）的位串数据用 INT8U 类型来保存时的数据值。
用于在协议栈内，通过 `IEC61850_DataAttributeData` 来设置或解析服务端客户端通信交互的双点位置数据。
其中，INT8U 作为位串数据使用时的前 2 bit （左边最高的 2 bit），代表实际的双点位置数据值。 */
typedef enum IEC61850DbPosValue
{
	IEC61850_DB_POS_OFF		= 0x00,	/*!< 中间状态（intermediate-state）  */
	IEC61850_DB_POS_FALSE	= 0x40,	/*!< 分闸（off） */
	IEC61850_DB_POS_TRUE	= 0x80,	/*!< 合闸（on） */
	IEC61850_DB_POS_INVALID	= 0xC0,	/*!< 故障状态（bad-state） */
} IEC61850DbPosValue;

/*!  行为模式（Mod、Beh）<br>
与 IEC61850-7-4-2010（DL/T 860.74-2014）的 "附录A" 的内容相对应。<br>
详细释义可以参照 IEC61850-7-4-2010（DL/T 860.74-2014）的 "附录A"。 */
typedef enum IEC61850_ModeAndBehaviourState
{
	IEC61850_MODE_ON = 1,			/*!< on */
	IEC61850_MODE_BLOCKED = 2,		/*!< on-blocked */
	IEC61850_MODE_TEST = 3,			/*!< test */
	IEC61850_MODE_TESTBLOCKED = 4,	/*!< test/blocked */
	IEC61850_MODE_OFF = 5,			/*!< off */
} IEC61850_ModeAndBehaviourState;

/*!    The states of Health (see 61850-7-4 IEC:2003 page 75) */
typedef enum IEC61850_HealthState
{
	IEC61850_HEALTH_OK	= 1,		/*!< OK ("Green") No problems, normal operation   */
	IEC61850_HEALTH_WARNING = 2,	/*!< Warning (yellow) minor problems, but in safe operation mode */
	IEC61850_HEALTH_ALARM = 3,		/*!< Alarm (red) severe problem, no operation possible */
} IEC61850_HealthState;

/*!	\brief	控制命令参数  */
typedef struct IEC61850_CommandParameter
{
	Boolean bTestMode;			/*!< 测试模式标记（Test） */
	S8 synchroCheck;			/*!< 同期检查标记（SynchroCheck） */
	S8 interlockCheck;			/*!< 互锁检查标记（Interlock-Check） */
	Boolean bStackGenerated;	/*!< 回调由内部堆栈条件触发标记<br>该成员会被 "取消回调函数" 使用。<br>（参照回调函数章节中对 IEC61850_ControlCancelCallback 的介绍） */
	enum eOriginatorCat orCat;	/*!< 发起者（orCat = Originator Catagory） */
	const char* orIdent;		/*!< 发起者标识（orIdent = Originator Identity） */
	U8 orIdentSize;				/*!< 发起者标识大小 */
	IEC61850_ModeAndBehaviourState localBeh; /*!< 行为模式状态 */
} IEC61850_CommandParameter;

struct IEC61850_Struct;

/*!	\brief	IEC61850 对象类型。<br>
是个指针类型。<br>
可由 `IEC61850_Create()` 接口创建并返回，并在其他 API 调用中作为必要的入参使用。<br>
IEC61850 对象应作为全局变量定义使用。单个装置所使用的 IEC61850 对象应全局唯一。  */
typedef struct IEC61850_Struct* IEC61850;

/*!	\brief	该枚举类型用于个别回调函数的返回值。<br>
其各个枚举值所代表的意义如下表，实际与同名的 eServiceError 所代表的意义相同。  */
typedef enum IEC61850_CallbackReturnServiceErrorCode
{
	IEC61850_CB_ERROR_NONE									= 0,	/*!< 无错误 */
	IEC61850_CB_ERROR_INSTANCE_NOT_AVAILABLE				= -1,	/*!< 实例不可用 */
	IEC61850_CB_ERROR_ACCESS_VIOLATION						= -2,	/*!< 访问违例 */
	IEC61850_CB_ERROR_PARAMETER_VALUE_INCONSISTENT			= -3,	/*!< 参数值不一致 */
	IEC61850_CB_ERROR_INSTANCE_LOCKED_BY_OTHER_CLIENT		= -4,	/*!< 实例被其他客户锁定 */
	IEC61850_CB_ERROR_TYPE_CONFLICT							= -5,	/*!< 类型冲突 */
	IEC61850_CB_ERROR_FAILED_DUE_TO_SERVER_CONSTRAINT		= -6,	/*!< 由于服务端约束失败 */
} IEC61850_CallbackReturnServiceErrorCode;

/*!	\brief	控制命令执行结果对应的附加原因码（AddCause）。用于控制服务。
	\details
	其类别与对应的解释，请参照 IEC61850-7-2-2010（DL/T 860.72-2013）的 20.5.2.9 章节的 "AddCause 附加的原因诊断" 内容。<br>

	AddCause 类型与值的映射关系，可参照 IEC61850-8-1-2011（DL/T 860.81-2016）中第 20.11 章节的 "表97  ACSI 额外原因值的映射"。<br>
	其中 `IEC61850_COMMAND_ERROR_NONE` (-1) 为 YX-PIS 协议栈内部使用的枚举值，其余的枚举值的含义与 IEC61850 协议要求一致。
	应使用 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 代表控制请求正常动作。

	大多数场合下，不需要用户主动决定控制命令响应的 AddCause，协议栈会自行判断决定。
	如需人为决定控制命令响应的 AddCause 的值（例如在 Operate 命令执行之前，运行测试不通过的场景下），也应参照 IEC61850 的协议要求，指定与实际控制状态机对应的、意义适当的 AddCause，不能随意指定。
*/
typedef enum eCommandAddCause
{
	IEC61850_COMMAND_ERROR_NONE 										= -1,	/*!< 无  */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_UNKNOWN							= 0,	/*!< 未知 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_NOT_SUPPORTED						= 1,	/*!< 不支持 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY		= 2,	/*!< 被开关机构闭锁 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_SELECT_FAILED						= 3,	/*!< 选择失败 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_INVALID_POSITION					= 4,	/*!< 无效位置(Pos in XCBR or XSWI) */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_POSITION_REACHED					= 5,	/*!< 到达位置 (Pos in XCBR or XSWI) */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION		= 6,	/*!< 执行中参数改变 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_STEP_LIMIT							= 7,	/*!< 步长限制 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_MODE					= 8,	/*!< 被模式闭锁 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_PROCESS					= 9,	/*!< 被过程闭锁 (EEHealth in XCBR or XSWI) */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_INTERLOCKING			= 10,	/*!< 被互锁闭锁  */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK			= 11,	/*!< 被检同期互锁  */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION		= 12,	/*!< 命令已在执行中 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_HEALTH					= 13,	/*!< 被健康状态闭锁  */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_1_OF_N_CONTROL						= 14,	/*!< 1对N控制 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_ABORTION_BY_CANCEL					= 15,	/*!< 因取消而异常终止 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_TIME_LIMIT_OVER					= 16,	/*!< 超时 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_ABORTION_BY_TRIP					= 17,	/*!< 因跳闸而异常终止 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_OBJECT_NOT_SELECTED				= 18,	/*!< 对象没被选择 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_OBJECT_ALREADY_SELECTED			= 19,	/*!< 对象已被选择  */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_NO_ACCESS_AUTHORITY				= 20,	/*!< 无访问权限 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_ENDED_WITH_OVERSHOOT				= 21,	/*!< 因超调而结束 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_ABORTION_DUE_TO_DEVIATION			= 22,	/*!< 因偏差而异常终止 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS		= 23,	/*!< 因通信中断而异常终止 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_COMMAND					= 24,	/*!< 因命令而闭锁 */
	IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE 								= 25,	/*!< 无 */
	IEC61850_COMMAND_ERROR_ADD_INCONSISTENT_PARAMETER					= 26,	/*!< 参数不一致 */
	IEC61850_COMMAND_ERROR_ADD_LOCKED_BY_OTHER_CLIENT					= 27,	/*!< 被其他客户锁定 */
} eCommandAddCause;

/*! IEC61850 对象角色类型<br>
服务端 或 客户端。对于 "服务端订阅端" ，其角色也是服务端。  */
typedef enum IEC61850_ClientServerFlag
{
	IEC61850_SERVER = 0,	/*!< 服务端  */
	IEC61850_CLIENT = 1,	/*!< 客户端  */
} IEC61850_ClientServerFlag;

/*! \brief	IEC61850 对象版本  */
typedef enum IEC61850_Ed1_Ed2_Flag
{
	IEC61850_Edition1 = 0,	/*!< 版本一 */
	IEC61850_Edition2 = 1,	/*!< 版本二（通常使用该版本） */
} IEC61850_Ed1_Ed2_Flag;

/*!  定值组数据的初始加载方式<br>
该枚举类型用于 IEC61850 对象的属性参数，用来指定服务端启动或重启时，定值组数据的初始加载动作。  */
typedef enum IEC61850_LoadSGDataFlag
{
	IEC61850_LOAD_LAST_SG_CHANGES	= 0,	/*!< 加载为最后一次修改过的定值。<br>若从来没有或修改过定值组的定值，则与 IEC61850_IGNORE_SG_CHANGES 无差别  */
	IEC61850_IGNORE_SG_CHANGES		= 1,	/*!< 无视定值的修改。<br>即，始终按照模型文件中的定义，来加载定值组。<br>包括初始激活的定值组号，以及该定值组号所对应的定值数据  */
} IEC61850_LoadSGDataFlag;

/*!  IEC61850 对象的数据映射模式<br>
该枚举类型用于 IEC61850 对象属性参数的 "数据映射模式" 成员（dataMapMode）  */
typedef enum IEC61850_DataMapMode
{
	IEC61850_MAP_MODE_DAID = 0,			/*!< 数据属性ID（DAID） */
	IEC61850_MAP_MODE_SADDR = 1,		/*!< 短地址（sAddr = Short Address） */
	IEC61850_MAP_MODE_REFERENCE = 2,	/*!< 引用（Reference） */
} IEC61850_DataMapMode;

/*!	IEC61850 对象的可选参数<br>
用于为创建的 IEC61850 对象添加额外属性。  */
typedef enum IEC61850_OptionFlag
{
	IEC61850_OPTION_NONE							= 0x00,		/*!< 无。是默认的 0 值。任何其他选项被设置，将覆盖并忽略该值 */
	IEC61850_OPTION_FLAG_TEST_MODE					= 0x01,		/*!< 设置服务器为测试模式（只用于内部测试用，不应由客户使用） */
	IEC61850_OPTION_BLOCK_WRITE_TO_CF				= 0x02,		/*!< 阻止对 FC=CF 数据的写操作。如果被设置，则不能对功能约束为 CF 的数据进行写操作（即，不能修改配置信息） */
	IEC61850_OPTION_SERVER_SEND_CONCLUDE_REQUEST	= 0x04,		/*!< 允许服务端向客户端发送一个结束请求  */
	IEC61850_OPTION_SERVER_SUBSCRIBE_GOOSE			= 0x08,		/*!< 允许服务端订阅 GOOSE 报文。由同时作为 GOOSE 订阅端的服务端使用 */
	IEC61850_OPTION_ALLOW_DUPLICATE_DAID			= 0x10,		/*!< **慎重使用** <br>允许包含重复 DAID 的模型文件被加载。<br>如果能够确保模型文件中不存在重复的 DAID，使用该选项可跳过模型加载时的 DAID 校重流程。<br>否则，使用该选项可能引起不可预见的结果。 */
	IEC61850_OPTION_UCA_TESTING						= 0x20,		/*!< **禁止使用** */
	IEC61850_OPTION_SLOW_LOAD						= 0x40,		/*!< **禁止使用** */
	IEC61850_OPTION_SYSTEMCORP_RESERVED				= 0x80,		/*!< **禁止使用** */
	IEC61850_OPTION_DEFAULT_INDEXED_REPORTING_FALSE	= 0x100,	/*!< 报告控制块默认indexed=false */
	IEC61850_OPTION_DISABLE_AUTO_FEEDBACK_CMD_TERM	= 0x200,	/*!< 取消增强安全控制流程的命令终止的自动反馈 */
	IEC61850_OPTION_DISABLE_CONTROL_CFDC_READ_ONLY	= 0x400,	/*!< 取消对控制模型中功能约束为 CF 和 DC 的数据的只读限制。<br>除非完全了解使用该选项可能导致的控制模型变化所产生的影响，否则不应使用。 */
	IEC61850_OPTION_ONLY_ALLOW_SE_EDITING			= 0x800,	/*!< 只允许编辑 CID 模型中 FC=SE 的定值数据。<br>使用该选项，模型中 FC=SG 的定值数据将不可编辑。 */
} IEC61850_OptionFlag;

/*! \brief 服务错误码（eServiceError） <br>
服务错误的类型，参照 IEC61850-7-2:2010（DL/T 860.72-2013）中第 6.1.2.6 章节的 "eServiceError（服务差错）类型"。<br>
MMS 版本对 eServiceError 类型与值的映射关系，参照 IEC61850-8-1-2011（DL/T 860.81-2016）中第 15.2 章节的 "表52  ACSI 服务错误值的映射"。  */
typedef enum eServiceError
{
	SERVICE_ERROR_NO_ERROR = 0,								/*!< 无差错（no-error） */
	SERVICE_ERROR_INSTANCE_NOT_AVAILABLE = 1,				/*!< 实例不可用（instance-not-available） */
	SERVICE_ERROR_INSTANCE_IN_USE = 2,						/*!< 实例在使用（instance-in-use） */
	SERVICE_ERROR_ACCESS_VIOLATION = 3,						/*!< 访问违例（access-violation） */
	SERVICE_ERROR_ACCESS_NOT_ALLOWED_IN_CURRENT_STATE = 4,	/*!< 在当前状态不允许访问（access-not-allowed-in-current-state） */
	SERVICE_ERROR_PRARMETER_VALUE_INAPPROPRIATE = 5,		/*!< 参数值不合适（parameter-value-inappropriate） */
	SERVICE_ERROR_PARAMETER_VALUE_INCONSISTENT = 6,			/*!< 参数值不一致（parameter-value-inconsistent） */
	SERVICE_ERROR_CLASS_NOT_SUPPORTED = 7,					/*!< 类不被支持（class-not-supported） */
	SERVICE_ERROR_INSTANCE_LOCKED_BY_OTHER_CLIENT = 8,		/*!< 实例由其他客户端闭锁（instance-locked-by-other-client） */
	SERVICE_ERROR_CONTROL_MUST_BE_SELECTED = 9,				/*!< 控制前必须选择（control-must-be-selected） */
	SERVICE_ERROR_TYPE_CONFLICT = 10,						/*!< 类型冲突（type-conflict） */
	SERVICE_ERROR_FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT = 11, /*!< 由于通信约束失败（failed-due-to-communications-constraint） */
	SERVICE_ERROR_FAILED_DUE_TO_SERVER_CONSTRAIANT = 12		/*!< 由于服务器约束失败（failed-due-to-server-constraint） */
} eServiceError;

/*!	\brief	文件名称最大长度。<br>
因不同的操作系统对文件名或文件路径有不同的最大长度限制，256 仅是一个相对通用的参考值。
实际使用协议栈时，需要注意确保不要出现超过操作系统最大长度限制的文件名或文件目录长度。  */
#define IEC61850_FILENAME_SIZE			256 

/*!	\brief	广义的时间字符串最大长度。  */
#define IEC61850_GENERALIZED_TIME_SIZE	30	

/*!	\brief	文件信息 */
typedef struct tFile
{
	char		fileName[IEC61850_FILENAME_SIZE];				/*!< 文件名 */
	char		lastModified[IEC61850_GENERALIZED_TIME_SIZE];	/*!< 最后的修改时间的字符串 e.g. YYYYMMDDHHMMSShhmmss.fffZ*/
	U32			fileSize;	/*!< 文件大小。单位为字节 */

	Boolean		bDirectory;	/*!< 是否是文件夹<br>  TRUE：文件夹<br>FALSE：文件 */
	Boolean		bHide;		/*!< 是否为隐藏的文件或目录<br>TRUE：隐藏<br>FALSE：非隐藏 */
} tFile;

/*!	\brief	文件属性  */
typedef struct tFileAttr
{
	tFile primaryFile;			/*!< 首要文件信息 */
	tFile* directoryEntries;	/*!< 文件目录条目集。<br>条目数量由 numOfDirectoryEntries 指定，需要遍历解析。 */
	U32 numOfDirectoryEntries;	/*!< 文件目录条目数量 */
} tFileAttr;

/*! \brief	客户端请求的文件服务调用类别  */
typedef enum IEC61850_FileCallType
{
	IEC61850_FILE_CALL_READ					= 1,	/*!< 读文件 */
	IEC61850_FILE_CALL_GET_ATTRIBUTES		= 2,	/*!< 获取文件属性 */
	IEC61850_FILE_CALL_DELETE				= 3,	/*!< 删除文件 */
	IEC61850_FILE_CALL_SET_FILE				= 4,	/*!< 写文件 */
	IEC61850_FILE_CALL_SET_FILE_COMPLETE	= 5,	/*!< 写文件完成 */
	IEC61850_FILE_CALL_SET_FILE_FAIL		= 6,	/*!< 写文件失败 */
} IEC61850_FileCallType;

/*! \brief	客户端请求的文件服务调用的响应码  */
typedef enum IEC61850_FileResponseCode
{
	IEC61850_FILE_RESPONSE_ACCEPT			= 0,	/*!< 请求被接受  */ 
	IEC61850_FILE_RESPONSE_ACCESS_DENIED	= 1,	/*!< 访问被拒绝  */ 
	IEC61850_FILE_RESPONSE_NON_EXISTENT		= 2,	/*!< 文件不存在  */ 
} IEC61850_FileResponseCode;

/*! \brief		定值组操作类型 */
typedef enum IEC61850_SettingGroup_Operation
{
	SG_SELECT_ACTIVE	= 0,	/*!< 选择激活定值组 回调传参SGCallback_Select结构体 */
	SG_SELECT_EDIT		= 1,	/*!< 选择编辑定值组 回调传参SGCallback_Select结构体 */
	SG_CONFIRM_EDIT		= 2,	/*!< 确认编辑定值组 回调传参char*为定值组控制块引用 */
	SG_GET_VALUE		= 3,	/*!< 获取定值组值 回调传参SGCallback_Data结构体 */
	SG_SET_VALUE		= 4,	/*!< 设置定值组值 回调传参SGCallback_Data结构体 */
	SG_GET_SGCB			= 5,	/*!< 读定值组控制块值 回调传参char*为定值组控制块引用 */
} IEC61850_SettingGroup_Operation;

/*! \brief	定值组回调传递的参数结构体
用于选择激活或编辑定值组的回调。 */
typedef struct SGCallback_Select
{
	char* reference;	/*!< 定值组控制块引用 */
	U8 sgNumber;		/*!< 定值组的组号 */
} SGCallback_Select;

/*! \brief		定值组回调传递的参数结构体。
用于选择激活或编辑定值组的回调。 */
typedef struct SGCallback_Data
{
	char* reference;		/*!< 定值组数据引用 */
	char* fc;				/*!< 定值组数据的功能约束 */
	IEC61850_DataType type;	/*!< 定值组数据类型 \see #IEC61850_DataType  */
	unsigned int size;		/*!< 定值组数据值大小 */
	void* data;				/*!< 定值组数据值 */
} SGCallback_Data;

/*! \brief		对于增强安全的控制对象的操作命令的控制结果。
用于命令终止回调函数。 */
typedef struct ControlResult
{
	char reference[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 控制对象的引用 */
	IEC61850_DataAttributeData ctlVal;					/*!< 控制值 */
	U32 orCat;											/*!< 控制请求的发起者（orCat = Originator Catagory） */
	U8 orIdent[64];										/*!< 控制请求的发起者标识（orIdent = Originator Identity） */
	U8 ctlNum;											/*!< 控制请求编号 */
	IEC61850_TimeStamp t;								/*!< 控制请求的时间戳 */
	Boolean test;										/*!< 控制请求的测试（Test）标志 */
	U8 check;											/*!< 控制请求的检查（Check）标志 */
	IEC61850_TimeStamp* operTm;							/*!< 时间激活控制请求的时间。在 CommandTermination 请求中固定为 0 值 */
	eCommandAddCause eCtlAddCause;						/*!< 控制请求的附加的原因诊断（AddCause） */
} ControlResult;

/*!	\brief	读回调。
	\details
	当客户端对服务端的数据进行读操作时，会在服务端被调用。
	该回调函数对应的读操作是 MMS Read 请求，`IEC61850_Read()`、`IEC61850_ReadDirect()` 接口会发起 MMS Read 请求动作。
	该回调函数无视服务端的数据映射模式。是否会被回调，仅取决于客户端请求读的数据，在服务端的模型中是否配置有 DAID，即：

	- 若客户端请求读的数据，在服务端的模型中配置有 DAID，
		则服务端将固定以 数据属性ID（ #IEC61850_MAP_MODE_DAID ）的数据映射模式来触发该回调函数的执行，
		`dataMap` 参数对应的实际数据类型固定为 const IEC61850_DataAttributeID *。
	- 若客户端请求读的数据，在服务端的模型中没有配置 DAID，
		则该回调函数不会被触发。

	若客户端请求读的数据是一个结构体类型（例如读一个包含多个 DA 的 DO 或 SDO），则该结构体中所有配置有 DAID 的数据属性，都会单独触发一次该回调函数。
	并非所有的读操作都可以触发该回调函数的执行。特定功能的读操作（例如读各类控制块等），不会触发该回调函数。
	该回调函数应固定返回  #IEC61850_CB_ERROR_NONE (0)，不应返回其他值。

	\ingroup 	ServerCallback

	\param[in]	userData		自定义用户数据
	\param[in]	dataMap			DAID。实际数据类型固定为 const IEC61850_DataAttributeID *。
	\param[in]	returnedValue	DAID 所对应数据的值。即，读到的数据值。 

	\return		成功返回 #IEC61850_CB_ERROR_NONE ，失败返回 enum #IEC61850_CallbackReturnServiceErrorCode 对应代码

	\see IEC61850_SetUserData(), IEC61850_Update(), IEC61850_ReadMultipleCallback

	<b>示例</b>
	\code
	IEC61850_CallbackReturnServiceErrorCode ReadCB(void* userData, const IEC61850_DataAttributeID* dataMap, IEC61850_DataAttributeData* returnedValue)
	{
		IEC61850_CallbackReturnServiceErrorCode errorCode = IEC61850_CB_ERROR_NONE;
		// 客户端对 dataMap 对应的数据属性请求了 MMS Read
		printf("Data DAID: ");
		IEC61850_PrintDataAttributeID(dataMap);
		printf("\n");

		printf("Data Value: ");
		IEC61850_PrintDataAttributeData(returnedValue);
		printf("\n");
		return errorCode;
	}
	\endcode
*/
typedef IEC61850_CallbackReturnServiceErrorCode (*IEC61850_ReadCallback)(void* userData, const void* dataMap, IEC61850_DataAttributeData* returnedValue);

/*!	\brief	多读回调。
	\details
	该回调函数与读回调（`IEC61850_ReadCallback`）的功能、触发条件等各个方面均相同，
	与读回调（`IEC61850_ReadCallback`）的唯一差异，在于单个 MMS Read 请求读的数据为结构体类型的情况。

	单个 MMS Read 请求读的数据为结构体数据时（例如读一个包含多个 DA 的 DO 或 SDO），
	该回调函数会将该结构体中配置有 DAID 的多个数据汇总到一起，统一回调一次，并通过 `count` 参数指示相应的数据数量。
	（读回调（`IEC61850_ReadCallback`）是结构体中每个配置有 DAID 的数据都单独回调一次）。

	单个 MMS Read 请求读的数据是一个单一的基本类型数据时（例如请求读一个最子级别的、基本数据类型的数据属性），
	该回调函数的动作与读回调（`IEC61850_ReadCallback`）无区别。（`count` 参数值将为 1。）
	指定使用该回调函数，将使读回调（`IEC61850_ReadCallback`）失效，无论是否有同时指定使用读回调（`IEC61850_ReadCallback`）。

	\ingroup	ServerCallback

	\param[in]	userData		自定义用户数据
	\param[in]	dataMap			DAID 列表。<br>
								该参数固定为 const IEC61850_DataAttributeID* 类型。<br>
								内容为 `IEC61850_DataAttributeID` 的数组，元素数量由 `count` 参数指定。
	\param[in]	returnedValue	DAID 列表所对应数据的值的列表。即，读到的数据值的列表。<br>
								内容为 `IEC61850_DataAttributeData` 的数组，元素数量由 `count` 参数指定。
	\param[in]	count			读到的数据数量

	\return	成功返回 #IEC61850_CB_ERROR_NONE ，失败返回 enum #IEC61850_CallbackReturnServiceErrorCode 对应的代码
	
	\see	IEC61850_SetUserData(), IEC61850_ReadCallback
	
	<b>示例</b>
	\code
	IEC61850_CallbackReturnServiceErrorCode ReadMultipleCB(void* userData, const IEC61850_DataAttributeID* dataMap, IEC61850_DataAttributeData* returnedValue, int count)
	{
		IEC61850_CallbackReturnServiceErrorCode errorCode = IEC61850_CB_ERROR_NONE;
		printf("Read data count: %d\n", count);
		for (int i = 0; i < count; i++) {
			printf("Data[%d] DAID: ", i + 1);
			IEC61850_PrintDataAttributeID(&dataMap[i]);
			printf("\n");

			printf("Data[%d] Value: ", i + 1);
			IEC61850_PrintDataAttributeData(&returnedValue[i]);
			printf("\n");
		}
		return  errorCode;
	}
	\endcode
*/
typedef IEC61850_CallbackReturnServiceErrorCode (*IEC61850_ReadMultipleCallback)(void* userData, const void* dataMap, IEC61850_DataAttributeData* returnedValue, int count);


/*!	\brief	写回调。
	\details
	当客户端对服务端的数据进行写操作时，会在服务端被调用。
	该回调函数对应的写操作是 MMS Write 请求，`IEC61850_Write()`、`IEC61850_WriteDirect()`  接口会发起 MMS Write 请求动作。
	该回调函数无视服务端的数据映射模式。是否会被回调，仅取决于客户端请求写的数据，在服务端的模型中是否配置有 DAID，即：

	- 若客户端请求写的数据，在服务端的模型中配置有 DAID，
		则服务端将固定以 数据属性ID（ #IEC61850_MAP_MODE_DAID ）的数据映射模式来触发该回调函数的执行，
		`dataMap` 参数对应的实际数据类型固定为 const IEC61850_DataAttributeID *。
	- 若客户端请求写的数据，在服务端的模型中没有配置 DAID，
		则该回调函数不会被触发。

	并非所有的写操作都可以触发该回调函数的执行。特定功能的写操作（例如控制命令等），不会触发该回调函数。
	该回调函数应固定返回  #IEC61850_CB_ERROR_NONE (0)，不应返回其他值。

	\ingroup 	ServerCallback

	\param[in]	userData	自定义用户数据
	\param[in]	dataMap		DAID。该参数固定为 const IEC61850_DataAttributeID* 类型。
	\param[in]	newValue	DAID 所对应数据的值。

	\return		成功返回 #IEC61850_CB_ERROR_NONE 失败返回 #IEC61850_CallbackReturnServiceErrorCode 对应的代码

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	IEC61850_CallbackReturnServiceErrorCode WriteCB(void* userData, const IEC61850_DataAttributeID* dataMap, const IEC61850_DataAttributeData* newValue)
	{
		IEC61850_CallbackReturnServiceErrorCode errorCode = IEC61850_CB_ERROR_NONE;
		// 客户端对 dataMap 对应的数据属性请求了 MMS Write
		printf("Data DAID: ");
		IEC61850_PrintDataAttributeID(dataMap);
		printf("\n");

		printf("Data Value: ");
		IEC61850_PrintDataAttributeData(newValue);
		printf("\n");
		return errorCode;
	}
	\endcode
*/
typedef IEC61850_CallbackReturnServiceErrorCode (*IEC61850_WriteCallback)(void* userData, const void* dataMap, const IEC61850_DataAttributeData* newValue);


/*!	\brief	数据更新回调
	\details
	该回调函数是数据订阅方触发的回调函数，用于从服务端发布的 报告、GOOSE、SV 中得知服务端的数据更新信息，进而触发和执行自己本地的期待动作（例如对比和同步本地数据）。
	数据订阅方通常是客户端，也可以是服务端。各有以下触发场景：

	- 数据订阅方为客户端：
		- 客户端接收到了服务端上送的报告；
		- 客户端作为 GOOSE 订阅端，接收到了所订阅的服务端发布的 GOOSE 消息；
		- 客户端作为 SV 订阅端，接收到了所订阅的服务端发布的 SV 消息。
	- 数据订阅方为服务端：
		- 服务端同时作为 GOOSE 订阅端，接收到了所订阅的服务端发布的 GOOSE 消息。

	报告、GOOSE 消息、SV 消息 中的每个数据会逐一触发该回调函数，
	`dataMap` 参数对应的是数据在数据订阅方模型中配置的数据属性映射信息，
	`newValue` 参数对应的是数据值。

	对于不同的触发数据源，该回调函数的动作和被调用的条件有所不同，详细如下：

	**报告触发**

	报告的接收方，固定为客户端。
	客户端接收到服务端上送的报告后，将在满足以下条件时调用该回调函数：

	1. 客户端的模型中，正确引用了与 \"报告数据\" 相匹配的服务端模型；
	2. 报告中的数据，在客户端引用的服务端模型中，配置有与 数据映射模式 匹配的 数据属性映射信息。
		即，需要满足以下匹配关系中的一种，才会触发回调函数：

		- 客户端的数据映射模式为 数据属性ID（ #IEC61850_MAP_MODE_DAID ），且报告对应的数据配置有 DAID；
			该种情况下，`dataMap` 参数传入的是数据的数据属性ID，对应的实际数据类型为 const IEC61850_DataAttributeID *。
		- 客户端的数据映射模式为 短地址（ #IEC61850_MAP_MODE_SADDR ），且报告对应的数据配置有 sAddr；
			该种情况下，`dataMap` 参数传入的是数据的短地址，对应的实际数据类型为 `const char*`。
		- 客户端的数据映射模式为 引用（ #IEC61850_MAP_MODE_REFERENCE ），（引用无需配置，不依赖额外的数据属性映射信息）。
			该种情况下，`dataMap` 参数传入的是数据的引用，对应的实际数据类型为 `const char*`。

		与客户端的 数据映射模式 相匹配的 数据属性映射信息 不存在时，报告不会触发该回调函数。

	**GOOSE 消息触发**

	GOOSE 订阅端可以是客户端，也可以是服务端。
	GOOSE 订阅端收到并处理 GOOSE 消息时，将在满足以下条件时，调用该回调函数：

	1. GOOSE 订阅端的模型中，正确引用了与 "订阅的 GOOSE 数据" 相匹配的 GOOSE 发布端（服务端）模型；
	2. GOOSE 订阅端收到的 GOOSE 消息，为需要处理的 GOOSE 消息，例如：
		- GOOSE 订阅端刚启动时首次收到的（每个订阅的 GOOSE 控制块上送的）的 GOOSE 消息；
		- 包含新事件（新 event）的 GOOSE 消息。（以常规 T0 间隔上送的 GOOSE 消息不会触发数据更新回调）
	3. GOOSE 消息中的数据，在 GOOSE 订阅端所引用的 GOOSE 发布端（服务端）模型中，配置有  DAID。
		未配置 DAID 的数据将不会触发回调。

	由 GOOSE 消息触发的数据更新回调，将无视 GOOSE 订阅端的数据映射模式。
	以上条件满足时，该回调函数将固定以数据属性ID（ #IEC61850_MAP_MODE_DAID ）的数据映射模式来回调，
	即，即使 GOOSE 订阅端的数据映射模式不是数据属性ID（ #IEC61850_MAP_MODE_DAID ），也会回调。
	回调时，`dataMap` 参数传入的数据属性映射信息固定为 DAID，对应的实际数据类型固定为 const IEC61850_DataAttributeID *。

	特殊的，
	若 GOOSE 订阅端为服务端，且订阅的 GOOSE 数据有被 Inputs 配置绑定了订阅端本地的数据，
	则该回调函数回调时，`dataMap` 参数将额外附带第二个 DAID：

	- 首个 DAID 不变，还是订阅端所引用的 GOOSE 发布端 模型中的 DAID；
	- 第二个 DAID，是由 Inputs 绑定的订阅端本地数据的 DAID。
		即，Inputs intAddr 指定的订阅端本地数据的 DAID。

	两个 DAID 只要有任意一个存在，回调函数就可以被触发。
	回调时，只有存在的 DAID 会有值。
	如果两个 DAID 都不存在，则不会触发回调。

	**SV 消息触发**

	SV 的订阅端，固定为客户端。
	客户端收到并处理 SV 消息时，将在满足以下条件时，调用该回调函数：

	1. 客户端的模型中，需要正确引用与 "订阅的 SV 数据" 相匹配的 SV 发布端（服务端）模型；
	2. SV 中的数据，在客户端所引用的 SV 发布端（服务端）模型中，配置有与 数据映射模式 匹配的 数据属性映射信息。
		客户端的数据映射模式为 数据属性ID（ #IEC61850_MAP_MODE_DAID ）或 短地址（ #IEC61850_MAP_MODE_SADDR ）时，SV 消息才会触发该回调函数。
		同时，需要保证数据属性映射信息存在，且与数据映射模式一致，
		即，满足以下匹配关系中的一种：

		- 客户端的数据映射模式为 数据属性ID（ #IEC61850_MAP_MODE_DAID ），且报告对应的数据配置有 DAID；
			该种情况下，`dataMap` 参数传入的是数据的数据属性ID，对应的实际数据类型为 const IEC61850_DataAttributeID *。
		- 客户端的数据映射模式为 短地址（ #IEC61850_MAP_MODE_SADDR ），且报告对应的数据配置有 sAddr；
			该种情况下，`dataMap` 参数传入的是数据的短地址，对应的实际数据类型为 `const char*`。

		与客户端的 数据映射模式 相匹配的 数据属性映射 信息不存在时，SV 消息不会触发该回调函数；
		客户端的数据映射模式为 引用（ #IEC61850_MAP_MODE_REFERENCE ）时，SV 消息也不会触发该回调函数。

	\ingroup	ServerAndClientCallback

	\param[in]	userData	自定义用户数据
	\param[in]	dataMap		数据属性映射。用于识别数据属性。<br>应基于回调方 IEC61850 对象的数据映射模式、角色、以及使用回调的场景，来确定 dataMap 传入的数据属性映射信息的类别，并按照相应的类别解析其值，以定位被更新数据的数据属性。
	\param[in]	newValue	数据发布方（服务端）更新的数据属性所对应数据的值。<br>通过 `dataMap` 确定触发回调的数据的数据属性。

	\return		none

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	void UpdateCB(void* userData, const void* dataMap, const IEC61850_DataAttributeData* newValue)
	{
		// dataMap 对应的数据属性值更新为了 newValue。

		// 假设 dataMap 为 DAID，
		IEC61850_DataAttributeID* daid = (IEC61850_DataAttributeID*)dataMap;	// 转换 dataMap 为 DAID
		if ((daid->field1 == 0) && (daid->field2 == 1) && (daid->field3 == 2) &&
			(daid->field4 == 3) && (daid->field5 == 4)) {    // 确认 DAID 对应的数据属性
			// 假设 dataMap 对应的是一个 INT32 类型的数据属性
			S32 int32NewVal = 0;	// 定义一个 INT32 类型的数据，
			int32NewVal = (*((S32*)newValue->pvData));	// 接收 newValue 传入的新数据值。
			// ...
		}

		// 或者，
		// 假设 dataMap 为短地址（sAddr），
		// const char* sAddr = (const char*)dataMap;	// 转换 dataMap 为 char*
		// if (strcmp(sAddr, "sAddrExample") == 0) {	// 确认 sAddr 对应的数据属性
		// 	// ...
		// }

		// 或者，
		// 假设 dataMap 为引用（reference），
		// const char* reference = (const char*)dataMap;	// 转换 dataMap 为 char*
		// if (strcmp(reference, "LDName/LNName.DOName.DAName") == 0) {	// 	确认引用对应的属性
		// 	// ...
		// }
	}
	\endcode
*/
typedef void (*IEC61850_UpdateCallback)(void* userData, const void* dataMap, const IEC61850_DataAttributeData* newValue);

/*!	\brief	(保留内容，暂不支持。**禁止使用**)

	\ingroup 	ServerAndClientCallback

	\param[in]	userData	自定义用户数据
	\param[in]	cbid		数据属性id
	\param[in]	newValues	数值指针
	\param[in]	length		数值长度

	\return		none

	\see IEC61850_SetUserData()
*/
typedef void (*IEC61850_ReportUpdateCallback)(void* userData, const void* cbid, const void* newValues, const unsigned int length);

/*!	\brief	报告控制块实例自动使能成功回调。
	\details
	用于报告服务。

	YX-PIS 的客户端会基于 ClientLN 的配置，在与服务端关联成功后，向服务端自动发起相应 RCB 实例的使能请求。

	当客户端基于 ClientLN 配置自动发起的 RCB 实例使能请求，成功使能了 RCB 实例时，该回调函数会在客户端被调用。
	客户端可通过该回调函数，得知这些 RCB 实例何时被使能成功。并借助该回调消息，对使能成功的 RCB 实例发起总召唤请求。

	该回调函数仅对客户端基于 ClientLN 配置自动发起的 RCB 实例使能动作有效。
	手动使能、手动取消使能并重新使能 RCB 实例的动作（例如通过调用 `IEC61850_ReportEnable()`、`IEC61850_SetBRCBValues()`、`IEC61850_SetURCBValues()` 接口发起的 RCB 实例使能动作），不会触发该回调函数。

	\ingroup 	ServerAndClientCallback

	\param[in]	userData	自定义用户数据
	\param[in]	rptInstRef	自动使能成功的 RCB 实例的引用。<br>例如：`LDName/LNName.RCBName01`
	\param[in]	buffered	自动使能成功的 RCB 实例的缓存类型。<br>TRUE：缓存报告控制块（BRCB）实例<br>FALSE：非缓存报告控制块（URCB）实例

	\return		none

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	void ReportAutoEnableSuccessCB(void* userData, const char* rptInstRef, Boolean buffered)
	{
		printf("%s Reference: [%s] has been enabled.\n", buffered ? "BRCB" : "URCB", rptInstRef);
		// requesting a general-interrogation
		IEC61850 myClient = GetMyServerClient();
		unsigned int serverIndex = 0;
		IEC61850_ReportGI(myClient, serverIndex, rptInstRef, buffered);
	}
	\endcode
*/
typedef void (*IEC61850_ReportAutoEnableSuccessCallback)(void*userData,const char* rptInstRef, Boolean buffered);

/*!	\brief	数据点品质可疑回调。
	\details
	用于通知 GOOSE 订阅端 GOOSE 数据的接收超时或中断，订阅端本地同步的 GOOSE 数据，应视为过期且品质可疑的数据。

	当 GOOSE 订阅端在 TAL（TimeAllowedToLive）时限内，没有接收到 GOOSE 发布端（服务端）重发的 GOOSE 消息时，该回调函数会在 GOOSE 订阅端被调用。触发回调的条件如下：

	1. GOOSE 订阅端的模型中，正确引用了与 \"订阅的 GOOSE 数据\" 相匹配的 GOOSE 发布端（服务端）的模型；
	2. GOOSE 消息中的数据，在 GOOSE 订阅端所引用的 GOOSE 发布端（服务端）模型中，配置有 DAID。

	该回调函数无视 GOOSE 订阅端的数据映射模式，将固定以数据属性ID（ #IEC61850_MAP_MODE_DAID ）的数据映射模式来触发回调，
	`dataMap` 参数对应的实际数据类型固定为 `const IEC61850_DataAttributeID*`。

	若 GOOSE 消息中的数据没有配置 DAID，则相应的 GOOSE 订阅数据不会触发该回调函数。

	\ingroup 	ServerAndClientCallback

	\param[in]	userData	自定义用户数据
	\param[in]	dataMap		数据属性映射。用于识别数据属性。<br>实际数据类型固定为 `const IEC61850_DataAttributeID*`。

	\return		none

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	void DataPointQuestionableCB(void* userData, const void* dataMap)
	{
		// dataMap 所对应数据的品质可疑
	}
	\endcode
*/
typedef void (*IEC61850_DataPointQuestionableCallback)(void* userData, const void* dataMap);

/*!	\brief	操作前选择测试回调。
	\details
	用于控制服务。可用于处理 带值操作前选择（SelectWithValue）控制命令的选择测试（Select Test）。

	当客户端请求了操作前选择命令（例如调用了 `IEC61850_ControlSelect()` 接口），
	且选择的是 SBOes 控制对象（即，操作前选择命令是带值的 SelectWithValue）时，服务端会调用该回调函数。
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	返回值指定为 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 代表选择测试通过（Test OK），后续的控制流程将继续处理。
	若该回调函数中无任何处理，应返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) ；
	返回值指定为 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 以外的其他有效 AddCause 枚举值，将视为选择测试未通过（Test Not OK），
	对应的 SelectWithValue 请求将以指定的 AddCause 响应和动作。指定返回的 AddCause 应为适用于当下控制状态机的合理 AddCause。

	\ingroup 	ServerCallback

	\param[in]	userData				自定义用户数据
	\param[in]	dataMap					数据属性映射。用于识别控制对象。<br>
										数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
										数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
										数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	selectTestParameters	控制参数信息

	\return		成功返回 #IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE ，失败返回适当的 附加的原因诊断 #eCommandAddCause

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	eCommandAddCause SelectTestCB(void* userData, const void* dataMap, const IEC61850_CommandParameter* selectTestParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;

		// 数据映射模式为数据属性ID（IEC61850_MAP_MODE_DAID）时，转换 dataMap 为 DAID
		IEC61850_DataAttributeID* daid = (IEC61850_DataAttributeID*)dataMap;
		IEC61850_PrintDataAttributeID(daid);	// 打印 DAID

		// 数据映射模式为短地址（IEC61850_MAP_MODE_SADDR）或引用（IEC61850_MAP_MODE_REFERENCE）时，转换 dataMap 为 char*
		// printf("sAddr(or reference) is: [%s]\n", (char*)dataMap);	// 打印 sAddr 或 reference

		if ((Boolean)selectTestParameters->synchroCheck) {
			Boolean synchroCheckOK = TRUE;
			synchroCheckOK = FALSE;
			// 执行同期检查 SynchroCheck
			if (!synchroCheckOK) {
				printf("SynchroCheck NG\n");
				return IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK;
			}
		}

		if ((Boolean)selectTestParameters->interlockCheck) {
			Boolean interlockCheckOK = TRUE;
			interlockCheckOK = FALSE;
			// 执行互锁检查 Interlock-Check
			if (!interlockCheckOK) {
				printf("Interlock-Check NG\n");
				return IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_INTERLOCKING;
			}
		}

		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ControlSelectTestCallback)(void* userData, const void* dataMap, const IEC61850_CommandParameter* selectTestParameters);

/*!	\brief	操作前选择回调。
	\details
	用于控制服务，可用于得知客户端请求了操作前选择 Select / SelectWithValue 控制命令。

	当客户端请求了 Select / SelectWithValue 操作前选择命令（例如调用了 `IEC61850_ControlSelect()` 接口）时，服务端将在选择测试通过之后，
	（即，选择测试回调函数 `IEC61850_ControlSelectTestCallback` 返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 之后），在执行操作前选择动作之前调用该回调函数。
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	控制对象将在该该回调函数返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 时被成功选择。

	建议把涉及拒绝操作前选择命令的情况，都放在该回调函数被调用之前的 `IEC61850_ControlSelectTestCallback` 回调函数中处理，
	该回调函数应始终返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) ，不应返回其他 AddCause。

	\ingroup 	ServerCallback

	\param[in]	userData			自定义用户数据
	\param[in]	dataMap				数据属性映射。用于识别控制对象。<br>
									数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
									数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
									数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	selectValue			操作前选择命令所附带的选择控制值。<br>
									对于选择 SBOes 控制对象的 SelectWithValue 命令，该值有效；<br>
									对于选择 SBOns 控制对象的 Select 命令，该值为 NULL。
	\param[in]	selectParameters	控制参数信息

	\return		成功返回 #IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE ，失败返回适当的 附加的原因诊断 #eCommandAddCause

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	eCommandAddCause SelectCB(void* userData, const void* dataMap, const IEC61850_DataAttributeData* selectValue, const IEC61850_CommandParameter* selectParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;

		// 数据映射模式为数据属性ID（IEC61850_MAP_MODE_DAID）时，转换 dataMap 为 DAID
		IEC61850_DataAttributeID* daid = (IEC61850_DataAttributeID*)dataMap;
		IEC61850_PrintDataAttributeID(daid);

		// 数据映射模式为短地址（IEC61850_MAP_MODE_SADDR）或引用（IEC61850_MAP_MODE_REFERENCE）时，转换 dataMap 为 char*
		// printf("sAddr(or reference) is: [%s]\n", (char*)dataMap);	// 打印 sAddr 或 reference

		if (selectValue) {
			// 操作前选择请求为适用于 SBOes 控制对象的 SelectWithValue 请求
		} else {
			// 操作前选择请求为适用于 SBOns 控制对象的 Select 请求
		}

		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ControlSelectCallback)(void* userData, const void* dataMap, const IEC61850_DataAttributeData* selectValue, const IEC61850_CommandParameter* selectParameters);


/*!	\brief	操作前选择超时回调。
	\details
	用于控制服务。可用于得知操作前选择（SBOns / SBOes）控制对象发生选择超时（sboTimeout）。

	当客户端请求的 Select / SelectWithValue 操作前选择命令（例如调用了 `IEC61850_ControlSelect()` 接口）成功选择了控制对象时，服务端会对其启动 "选择超时" 的计时器，时限由操作前选择控制对象的 sboTimeout 数据属性决定，未配置则默认为 30 秒。若服务端在 sboTimeout 的时限内，没有接收到客户端对于该控制对象的 Operate / TimeActivatedOperate 操作命令，则已被选择的控制对象，将因择超时而返回未被选择（Unselected）状态。

	当操作前选择的控制对象发生选择超时时，服务端会调用该回调函数。
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	该回调函数应始终返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) ，不应返回其他 AddCause。

	\ingroup 	ServerCallback

	\param[in]	userData	自定义用户数据
	\param[in]	dataMap		数据属性映射。用于识别控制对象。<br>
							数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
							数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
							数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	selectValue	操作前选择命令所附带的选择控制值。<br>
							对于选择 SBOes 控制对象的 SelectWithValue 命令，该值有效；<br>
							对于选择 SBOns 控制对象的 Select 命令，该值为 NULL。

	\return		成功返回 #IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE ，失败返回适当的 附加的原因诊断 #eCommandAddCause

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	eCommandAddCause SelectTimeoutCB(void* userData, const void* dataMap, const IEC61850_DataAttributeData* selectValue)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;
		// dataMap 对应的控制对象发生操作前选择超时。已由 "准备就绪(Ready)" 状态变为 "未被选择(Unselected)" 状态

		// 数据映射模式为数据属性ID（IEC61850_MAP_MODE_DAID）时，转换 dataMap 为 DAID
		IEC61850_DataAttributeID* daid = (IEC61850_DataAttributeID*)dataMap;
		IEC61850_PrintDataAttributeID(daid);	// 打印 DAID

		// 数据映射模式为短地址（IEC61850_MAP_MODE_SADDR）或引用（IEC61850_MAP_MODE_REFERENCE）时，转换 dataMap 为 char*
		// printf("sAddr(or reference) is: [%s]\n", (char*)dataMap);	// 打印 sAddr 或 reference

		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ControlSelectTimeoutCallback)(void* userData, const void* dataMap, const IEC61850_DataAttributeData* selectValue);

/*!	\brief	运行测试回调。
	\details
	用于控制服务，可用于处理 Operate / TimeActivatedOperate 操作命令的运行测试（Operative Test）。

	当客户端请求了 Operate / TimeActivatedOperate 操作命令（例如调用了 `IEC61850_ControlOperate()` 接口）时，服务端会在操作时间（operTm）到达时调用该回调函数。对于 Operate 请求，操作时间的到达时刻为即刻；对于 TimeActivatedOperate 请求，操作时间的到达时刻为操作请求中指定的时刻。
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	其返回值指定为 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25)，代表运行测试通过（Operative Test OK），后续的控制流程将继续处理。
	若该回调函数中无任何处理，应返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25)；

	若返回值指定为 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 以外的其他有效 AddCause 枚举值，则视为运行测试不通过（Operative Test Not OK），
	对应的 Operate / TimeActivatedOperate 操作命令将以指定的 AddCause 响应和动作。指定返回的 AddCause 应为适用于当下控制状态机的合理 AddCause。

	\ingroup 	ServerCallback

	\param[in]	userData				自定义用户数据
	\param[in]	dataMap					数据属性映射。用于识别控制对象。<br>
										数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
										数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
										数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	operativeTestParameters	控制参数信息

	\return		成功返回 #IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE ，失败返回适当的 附加的原因诊断 #eCommandAddCause

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	eCommandAddCause OperativeTestCB(void* userData, const void* dataMap, const IEC61850_CommandParameter* operativeTestParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;

		// 数据映射模式为数据属性ID（IEC61850_MAP_MODE_DAID）时，转换 dataMap 为 DAID
		IEC61850_DataAttributeID* daid = (IEC61850_DataAttributeID*)dataMap;
		IEC61850_PrintDataAttributeID(daid);

		// 数据映射模式为短地址（IEC61850_MAP_MODE_SADDR）或引用（IEC61850_MAP_MODE_REFERENCE）时，转换 dataMap 为 char*
		// printf("sAddr(or reference) is: [%s]\n", (char*)dataMap);	// 打印 sAddr 或 reference

		if ((Boolean)operativeTestParameters->synchroCheck) {
			Boolean synchroCheckOK = TRUE;
			synchroCheckOK = FALSE;
			// 执行同期检查 SynchroCheck
			if (!synchroCheckOK) {
				printf("SynchroCheck NG\n");
				return IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK;
			}
		}

		if ((Boolean)operativeTestParameters->interlockCheck) {
			Boolean interlockCheckOK = TRUE;
			interlockCheckOK = FALSE;
			// 执行互锁检查 Interlock-Check
			if (!interlockCheckOK) {
				printf("Interlock-Check NG\n");
				return IEC61850_COMMAND_ERROR_ADD_CAUSE_BLOCKED_BY_INTERLOCKING;
			}
		}

		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ControlOperativeTestCallback)(void* userData, const void* dataMap, const IEC61850_CommandParameter* operativeTestParameters);


/*!	\brief	操作回调。
	\details
	用于控制服务，可用于得知客户端请求了操作 Operate / TimeActivatedOperate 控制命令。

	当客户端请求了 Operate / TimeActivatedOperate 操作命令（例如调用了 `IEC61850_ControlOperate()` 接口）时，服务端将在运行测试通过（Operative Test OK）之后，
	（即，运行测试回调函数 `IEC61850_ControlOperativeTestCallback` 返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 之后），调用该回调函数。
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	服务端可基于该回调函数，触发和执行操作命令对应的实际控制动作，通常包括：

	- 识别客户端请求操作的控制对象以及控制值；
		（例如客户端请求操作开关控制器逻辑设备的 \"开关三相分合\" 状态 CSWI.Pos 为分或合）；
	- 对实际的物理设备执行客户端请求的操作动作；
		（例如服务端去实际控制物理开关设备的分或合）；
	- 等待并校验实际设备反馈的操作结果；
		（例如物理设备开关状态是否有成功变位到请求控制的分或合状态）；
	- 基于实际物理设备反馈的操作结果，更新控制对象对应的状态值。
		（例如依据物理开关设备受控后变化到的分或合状态，更新其对应开关控制器逻辑设备的 \"开关三相分合\" 状态值 CSWI.Pos.stVal 为 on 或 off）。

	其中，服务端对物理设备执行操作的动作，以及操作后对控制对象状态值的更新动作，都应该在该回调函数正常返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 之后执行。

	指定返回值为 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25)，代表操作命令已被服务端接受。
	通常应固定返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25)，无论服务端实际是否执行了操作物理设备和更新状态值的动作；

	指定返回值为 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) 以外的其他有效 AddCause 枚举值，则视为操作执行异常，
	对应的 Operate / TimeActivatedOperate 操作命令将以指定的 AddCause 响应和动作。指定返回的 AddCause 应为适用于当下控制状态机的合理 AddCause。

	\ingroup 	ServerCallback

	\param[in]	userData			自定义用户数据
	\param[in]	dataMap				数据属性映射。用于识别控制对象。<br>
									数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
									数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
									数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	operateValue		操作命令所附带的控制值
	\param[in]	operateParameters	控制参数信息

	\return		成功返回 #IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE ，失败返回适当的 附加的原因诊断 #eCommandAddCause

	\see IEC61850_SetUserData()

	<b>示例</b>
	以下以客户端请求操作 CSWI.Pos 时的操作回调为例。<br>
	CSWI.Pos 的控制值是 BOOLEAN 类型；CSWI.Pos 的状态值（CSWI.Pos.stVal）是 Dbpos 类型。
	数据映射模式为数据属性ID（`IEC61850_MAP_MODE_DAID`）的操作回调函数例子：
	\code
	eCommandAddCause OperateCB(void* userData, const void* dataMap, const IEC61850_DataAttributeData* operateValue, const IEC61850_CommandParameter* operateParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;

		// 基于 dataMap 的值，来识别控制对象，
		// 进而确定由 operateValue 参数传入的 "控制值" 的数据类型，
		// 以及要实际控制的物理设备，和控制完成后需要更新的 "状态值" 的数据类型和数据属性映射信息。

		// 即，在服务端的模型（例如 server.cid）中，
		// 找到 dataMap 对应的数据属性（CSWI.Pos.stVal），
		// 找到后，可确定其所属的控制对象（CSWI.Pos），
		// 进而确定其 "控制值" 为 BOOLEAN 类型，"状态值"（CSWI.Pos.stVal）为 Dbpos 类型，
		// 记录 "状态值"（CSWI.Pos.stVal）的数据属性映射信息，用于更新状态值。

		// 转换 dataMap 参数为 DAID。
		// 该 DAID 是服务端模型中，为客户端请求操作的控制对象的 "状态值"（CSWI.Pos.stVal）绑定的 DAID。
		IEC61850_DataAttributeID* ctlID = (IEC61850_DataAttributeID*)dataMap;

		// 此处假设 dataMap 传入的 DAID 为 [0,1,2,3,4]
		// 执行相应的处理逻辑
		if ((ctlID->field1 == 0)
			&& (ctlID->field2 == 1)
			&& (ctlID->field3 == 2)
			&& (ctlID->field4 == 3)
			&& (ctlID->field5 == 4)) {
			// 控制对象 CSWI.Pos 的 "控制值" 是 BOOLEAN 类型，
			// 按 BOOLEAN 类型解析 operateValue 传入的控制值。
			Boolean ctlVal = *(Boolean*)operateValue->pvData;

			// return IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;	// 令该回调函数返回 IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE
			// 并在该回调函数之外，执行对物理设备的操作，以及对状态值的更新处理。
			// 以下的示例代码仅用于理解控制流程。

			// 根据客户端请求的控制值，决定实际操作物理设备所使用的控制值。
			eDbPosValues physicalOperVal = DBPOS_OFF;	// 操作物理设备要使用的 Dbpos 操作值
			// 将客户端请求的 BOOLEAN 控制值，转换为操作物理设备要使用的 Dbpos 操作值。
			if (ctlVal == FALSE) {
				physicalOperVal = DBPOS_OFF;	// BOOLEAN 的控制值 FALSE，转换为 Dbpos 的状态值 off
			} else {
				physicalOperVal = DBPOS_ON;	// BOOLEAN 的控制值 TRUE，转换为 Dbpos 的状态值 on
			}

			// 此时，服务端应依据客户端请求的控制值，去实际 "操作" 物理设备。
			// （服务端对实际物理设备的操作控制，应由服务端自定义实现）
			// 同时，服务端应跟踪物理设备的操作情况，识别并保存物理设备反馈的实际操作结果。

			// 保存物理设备操作后的状态结果。
			// 服务端需要基于该结果，对控制对象的 "状态值" 做更新。
			eDbPosValues stVal = DBPOS_ON;	// 此处假设物理设备反馈的操作结果为 on

			// 分析服务端对物理设备的操作结果，根据情况，做控制对象 "状态值" 的更新处理。
			if (stVal == physicalOperVal	// 物理设备成功变位到客户端 "操作" 命令所请求的状态。（对于 CSWI.Pos.stVal 来说为 on 或 off）
				|| stVal == DBPOS_INTERMEDIATE || stVal == DBPOS_BAD) {	// 物理设备变位到了无效位置
				// 准备执行 "状态值" 的更新处理。
				// 可基于 DAID / sAddr / reference 的任意一种来做数据更新，
				// 此处以通过 DAID 来更新 "状态值" 为例。

				// 准备控制对象的 "状态值"（CSWI.Pos.stVal）的 DAID。（这里实际就是 dataMap 传入的 DAID）
				IEC61850_DataAttributeID daid = { 0, 1, 2, 3, 4 };

				// 准备控制对象 "状态值"（CSWI.Pos.stVal）的数据。
				IEC61850_DataAttributeData stValData = { 0 };
				stValData.type = IEC61850_DATATYPE_DBPOS;	// 指定数据类型。（CSWI.Pos.stVal 为 DBPos 类型）
				stValData.bitLength = IEC61850_DBPOS_BITSIZE;	// 指定数据大小（DBPos 数据的大小）
				stValData.pvData = &stVal;	// 指定数据属性的值为物理设备反馈的真实状态值

				// 调用数据更新接口，更新该控制对象的 "状态值"（CSWI.Pos.stVal）。
				IEC61850_ErrorCode eErrorCode = IEC61850_ERROR_NONE;
				IEC61850 myServer = GetMyServerClient();	// 获取 IEC61850 对象
				eErrorCode = IEC61850_Update(myServer, &daid, &stValData, 1);	// 通过 DAID 更新数据
				if (eErrorCode != IEC61850_ERROR_NONE) {
					// "状态值" 更新失败。
				} else {
					// "状态值" 更新成功。
				}
			} else {	// 物理设备未成功变位
				// 不更新 "状态值"。
				// 协议栈会在 operTimeout 的时间后，判定本次"操作"超时。
			}
		}
		return cmdAddCause;
	}
	\endcode

	数据映射模式为短地址（`IEC61850_MAP_MODE_SADDR`）的操作回调函数例子：
	\code
	eCommandAddCause OperateCB(void* userData, const void* dataMap, const IEC61850_DataAttributeData* operateValue, const IEC61850_CommandParameter* operateParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;

		// 转换 dataMap 为短地址。即，"状态值"（CSWI.Pos.stVal）的 sAddr
		const char* sAddr = (const char*)dataMap;

		// 基于短地址识别控制对象，并进入对应的处理逻辑。
		// 此处假设 dataMap 传入的短地址为 "stValsAddrExample"
		if (strcmp(sAddr, "stValsAddrExample") == 0) {
			// 依据识别到的控制对象，来判断由 operateValue 参数传入的 "控制值" 的数据类型，并解析传入的 "控制值"。
			Boolean ctlVal = *(Boolean*)operateValue->pvData;	// 双点位置（Dbpos）的 "控制值" 是 BOOLEAN 类型。

			// return IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;	// 令该回调函数返回 IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE
			// 并在该回调函数之外，执行对物理设备的操作，以及对状态值的更新处理。
			// 以下的示例代码仅用于理解控制流程。

			// 依据 "控制值" 去操作实际的物理设备，并保存物理设备操作后的状态结果。
			eDbPosValues stVal = DBPOS_ON;	// 应根据物理设备反馈的状态赋值

			// 准备执行 "状态值" 的更新处理。
			// 可基于 DAID / sAddr / reference 的任意一种来做数据更新，
			// 此处以通过 sAddr 来更新 "状态值" 为例。

			// 准备更新用的 "状态值"（CSWI.Pos.stVal） 的短地址。（这里实际就是 dataMap 传入的 sAddr）
			char* sAddrList[1] = { "stValsAddrExample" };	// 此处假设 "状态值" 的短地址为 "stValsAddrExample"

			// 准备更新用的 "状态值"（CSWI.Pos.stVal）的数据。
			IEC61850_DataAttributeData stValData = { 0 };
			stValData.type = IEC61850_DATATYPE_DBPOS;
			stValData.bitLength = IEC61850_DBPOS_BITSIZE;
			stValData.pvData = &stVal;

			// 调用数据更新接口，更新该控制对象在服务端中的 "状态值"（CSWI.Pos.stVal）。
			IEC61850_ErrorCode eErrorCode = IEC61850_ERROR_NONE;
			IEC61850 myServer = GetMyServerClient();
			eErrorCode = IEC61850_UpdateWithShortAddr(myServer, &sAddrList, &stValData, 1);	// 通过 sAddr 更新数据
			if (eErrorCode != IEC61850_ERROR_NONE) {
				// "状态值" 更新失败。
			} else {
				// "状态值" 更新成功。
			}
		}
		return cmdAddCause;
	}
	\endcode

	数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）的操作回调函数例子：
	\code
	eCommandAddCause OperateCB(void* userData, const void* dataMap, const IEC61850_DataAttributeData* operateValue, const IEC61850_CommandParameter* operateParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;

		// 转换 dataMap 为引用
		const char* reference = (const char*)dataMap;

		// 通过 dataMap 传入的引用，为请求控制的数据对象的引用。
		// 需要注意的是，引用路径仅到控制对象的数据对象层级，
		// 即，引用的值是 "LDName/LNName.DOName"，而不是 "LDName/LNName.DOName.Oper.ctlVal"

		// 基于引用识别控制对象
		if (strcmp(reference, "LDName/CSWI0.Pos") == 0) {
			// 依据识别到的控制对象，来判断由 operateValue 参数传入的 "控制值" 的数据类型，并解析传入的 "控制值"。
			Boolean ctlVal = *(Boolean*)operateValue->pvData;	// 双点位置（Dbpos）的 "控制值" 是 BOOLEAN 类型。

			// return IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;	// 令该回调函数返回 IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE
			// 并在该回调函数之外，执行对物理设备的操作，以及对状态值的更新处理。
			// 以下的示例代码仅用于理解控制流程。

			// 依据 "控制值" 去操作实际的物理设备，并保存物理设备操作后的状态结果。
			eDbPosValues stVal = DBPOS_ON;	// 应根据物理设备反馈的状态赋值

			// 准备执行 "状态值" 的更新处理。
			// 可基于 DAID / sAddr / reference 的任意一种来做数据更新，
			// 此处以通过 引用 来更新 "状态值" 为例。

			// 准备更新用的 "状态值"（CSWI.Pos.stVal） 的引用。
			char* stValRef = "ServerIEDExample/CSWI0.Pos.stVal";	// 引用值仅为示例

			// 准备更新用的 "状态值"（CSWI.Pos.stVal）的数据。
			IEC61850_DataAttributeData stValData = { 0 };
			stValData.type = IEC61850_DATATYPE_DBPOS;
			stValData.bitLength = IEC61850_DBPOS_BITSIZE;
			stValData.pvData = &stVal;

			// 调用数据更新接口，更新该控制对象在服务端中的 "状态值"（CSWI.Pos.stVal）。
			IEC61850 myServer = GetMyServerClient();
			IEC61850_ErrorCode eErrorCode = IEC61850_UpdateWithReference(myServer, stValRef, &stValData);	// 通过引用更新数据
			if (eErrorCode != IEC61850_ERROR_NONE) {
				// "状态值" 更新失败。
			} else {
				// "状态值" 更新成功。
			}
		}
		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ControlOperateCallback)(void* userData, const void* dataMap, const IEC61850_DataAttributeData* operateValue, const IEC61850_CommandParameter* operateParameters);

/*!	\brief	取消回调。
	\details
	用于控制服务。该回调函数会在以下场景下被服务端调用：

	- 当客户端请求了 Cancel 取消命令（例如调用了 `IEC61850_ControlCancel()` 接口），服务端会在接受 Cancel 命令的执行时调用该回调函数。
	- 当客户端对已经选择成功了的操作前选择（SBOns 或 SBOes）控制对象，请求执行 Opeate / TimeActivatedOperate 命令时，
		若因运行测试未通过（Operative Test Not OK）等异常原因，被服务端撤销了选择状态并终止执行控制操作时，服务端也会调用该回调函数。
		此种情况下，同时会在 `cancelParameters` 参数中标记 "回调由内部堆栈条件触发标记（bStackGenerated）" 的成员值为 TRUE，用于告知客户端控制对象的选择状态被取消。

	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	该回调函数通常仅应返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) ，不应返回其他 AddCause。
	特殊的，令该回调函数返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NOT_SUPPORTED` (1)，可以拒绝对控制对象执行的 Cancel 命令。

	\ingroup 	ServerCallback

	\param[in]	userData			自定义用户数据
	\param[in]	dataMap				数据属性映射。用于识别控制对象。<br>
									数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
									数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
									数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	cancelParameters	控制参数信息

	\return		成功返回 #IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE ，失败返回适当的 附加的原因诊断 #eCommandAddCause

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	eCommandAddCause CancelCB(void* userData, const void* dataMap, const IEC61850_CommandParameter* cancelParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;
		// 客户端请求取消对 dataMap 对应控制对象的控制请求

		// 数据映射模式为数据属性ID（IEC61850_MAP_MODE_DAID）时，转换 dataMap 为 DAID
		IEC61850_DataAttributeID* daid = (IEC61850_DataAttributeID*)dataMap;
		IEC61850_PrintDataAttributeID(daid);	// 打印 DAID

		// 数据映射模式为短地址（IEC61850_MAP_MODE_SADDR）或引用（IEC61850_MAP_MODE_REFERENCE）时，转换 dataMap 为 char*
		// printf("sAddr(or reference) is: [%s]\n", (char*)dataMap);	// 打印 sAddr 或 reference

		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ControlCancelCallback)(void* userData, const void* dataMap, const IEC61850_CommandParameter* cancelParameters);


/*!	\brief	命令终止回调。(仅对应 CommandTermination_req+)
	\details
	用于控制服务。客户端可基于该回调函数，得知服务端对客户端请求的操作命令的最终执行结果。

	当客户端接收到服务端上送的 CommandTermination 肯定请求（意味着 \"操作\" 命令以 \"成功\" 的结果结束）时，客户端会调用该回调函数。
	（若服务端上送的是 CommandTermination 否定请求（意味着 \"操作\" 命令以 \"失败\" 的结果结束），则客户端不会调用该回调函数，而是会调用 #IEC61850_ErrorCallback 回调函数。）
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。

	只有客户端对增强安全的（DOes 或 SBOes）控制对象执行 Operate / TimeActivatedOperate 操作命令时，服务端才会在控制流程的最后上送 CommandTermination 请求给客户端。
	对于控制常规安全的（DOns 或 SBOns）控制对象的场景，不涉及 CommandTermination 请求的上送，不会触发该回调函数的执行。

	\ingroup 	ClientCallback

	\param[in]	userData		自定义用户数据
	\param[in]	dataMap			数据属性映射。用于识别控制对象。<br>
								数据映射模式为数据属性ID（ #IEC61850_MAP_MODE_DAID ）时，对应的是控制对象 \"状态值\" 的 DAID，对应的数据类型是 `IEC61850_DataAttributeID*`；<br>
								数据映射模式为短地址（ #IEC61850_MAP_MODE_SADDR ）时，对应的是控制对象 \"状态值\" 的 sAddr，对应的数据类型是 `char*`；<br>
								数据映射模式为引用（ #IEC61850_MAP_MODE_REFERENCE ）时，对应的是控制对象的引用，对应的数据类型是 `char*`。
	\param[in]	controlResult	控制结果信息<br>仅对应 CommandTermination_req+ 的结果。

	\return		该回调函数应始终返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) ，不应返回其他 AddCause。

	\see IEC61850_SetUserData()
*/
typedef eCommandAddCause (*IEC61850_ControlCommandTerminationCallback)(void* userData, const void* dataMap, const ControlResult* controlResult);


/*!	\brief	错误回调。
	\details
	在客户端使用。可用于得知控制命令执行失败的相关错误信息（主要是 "附加的原因诊断（AddCause）" 信息）。

	客户端对增强安全的控制对象的操作（Operate）命令执行失败时，服务端会上送一个 CommandTermination 否定请求，
	内容为 LastApplError 的 MMS Information Report，其中会附带控制请求执行失败的相关错误信息（主要为 AddCause）。
	当客户端接收到内容为 LastApplError 的 MMS Information Report 时，该回调函数会在客户端被调用。
	回调的前提是，服务端的模型中，有为控制对象的 \"状态值\" 配置有与数据映射模式一致的数据属性映射。
	（关于 LastApplError 的说明，可以参照 IEC61850-8-1-2011（DL/T 860.81-2016）的第 20.11 章节的 "表96"）

	`dataMap` 参数对应控制对象控制值的数据映射信息（DAID 或 sAddr）。
	`errorParameters` 参数将传递 LastApplError 中附带的 \"错误（Error）\" 和 \"附加的原因诊断（AddCause）\" ，以及与控制命令对应的数据信息。

	\ingroup 	ServerCallback

	\param[in]	userData		自定义用户数据
	\param[in]	dataMap			数据属性映射。用于识别数据属性。<br>即，LastApplError 所对应的数据点的 DAID。<br>实际数据类型固定为 const IEC61850_DataAttributeID *。
	\param[in]	errorParameters	错误消息信息

	\return		该回调函数应始终返回 `IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE` (25) ，不应返回其他 AddCause。

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	eCommandAddCause ErrorCB(void* userData, const void* dataMap, const struct IEC61850_ErrorParameters* errorParameters)
	{
		eCommandAddCause cmdAddCause = IEC61850_COMMAND_ERROR_ADD_CAUSE_NONE;
		printf("The LastApplError of \"%s/%s\":\n", errorParameters->domainName, errorParameters->itemName);
		printf("\t Error: (%d) %s\n", (int)errorParameters->iErrorType, errorParameters->errorType);
		printf("\t AddCause: (%d) %s\n", (int)errorParameters->iErrorCause, errorParameters->errorCause);
		printf("\t DAID: ");
		IEC61850_PrintDataAttributeID((IEC61850_DataAttributeID*)dataMap);
		printf("\n");
		return cmdAddCause;
	}
	\endcode
*/
typedef eCommandAddCause (*IEC61850_ErrorCallback)(void* userData, const void* dataMap, const IEC61850_ErrorParameters* errorParameters);

/*!	\brief	连接状态回调。
	\details
	用于得知客户端与服务端连接状态的变化。
	当客户端与服务端的连接状态发生变化时（例如关联丢失，或者重新关联时），该回调函数会在客户端被调用。

	\ingroup 	ClientCallback

	\param[in]	userData				自定义用户数据
	\param[in]	connectedServersArray	服务端的连接状态列表

	\see IEC61850_SetUserData() , IEC61850_GetConnectionsList()

	<b>示例</b>
	\code
	void ConnectionStatusCB(void* userData, struct IEC61850_ServerStatusArray connectedServersArray)
	{
		// 客户端与服务端的连接状态发生变化
	}
	\endcode
*/
typedef void (*IEC61850_ConnectionStatusCallback)(void* userData, IEC61850_ServerStatusArray connectedServersArray);

/*!	\brief	时间戳回调。
	\details
	用于替代 YX-PIS 协议栈内置的方法，以自定义的方法计算和提供当前时间。

	YX-PIS 协议栈中，服务端和客户端会通过调用 `IEC61850_GetTime()` 接口来获取当前时间。
	协议栈已经对 `IEC61850_GetTime()` 接口内计算和获取当前时间的方法，做了基本的多平台环境适配，通常情况下无需定义和使用该回调函数。

	若该回调函数在 IEC61850 对象的属性参数中未被指定，该回调函数不会被调用。`IEC61850_GetTime()` 接口将按内置的默认方法获取和返回当前时间；
	若该回调函数在 IEC61850 对象的属性参数中有被指定，则该回调函数将在调用 `IEC61850_GetTime()` 接口时被调用。用户需要在该回调函数内实现对当前时间的获取和计算，并通过 `CurrentTime` 参数传出，随后 `IEC61850_GetTime()` 接口将返回由该回调函数提供的时间。

	\ingroup 	ServerandClientCallback

	\param[in]	userData	自定义用户数据
	\param[in]	timestamp	以自定义的方法获取和计算的当前时间

	\return		无返回值

	\see	IEC61850_SetUserData()

	<b>示例</b>
	\code
	void TimeStampCB(void* userData, IEC61850_TimeStamp* timestamp)
	{
		// 按自定义的方法获取当前时间，并赋值给 timestamp 参数
		timestamp->seconds = 1674448496;
	}
	\endcode
*/
typedef void (*IEC61850_TimeStampCallback)(void* userData, IEC61850_TimeStamp* timestamp);

/*!	\brief	文件回调。
	\details
	用于文件服务。可用于得知客户端请求的文件读写服务类别，以及请求的文件信息。
	该回调函数会在客户端请求了文件相关的 ACSI 时，在服务端被调用。

	\ingroup 	ServerCallback

	\param[in]	userData		自定义用户数据
	\param[in]	fileCallType	请求的文件调用类别。用于指示客户端请求的文件服务。
	\param[in]	fileAttributes	文件属性信息

	\return	文件请求响应码 #IEC61850_FileResponseCode

	\see IEC61850_SetUserData()

	<b>示例</b>
	\code
	enum IEC61850_FileResponseCode FileCB(void* userData, enum IEC61850_FileCallType fileCallType, struct tFileAttr* fileAttributes)
	{
		enum IEC61850_FileResponseCode responseCode = IEC61850_FILE_RESPONSE_ACCEPT;
		U32 fileIndex = 0;

		switch (fileCallType)
		{
		case IEC61850_FILE_CALL_READ:
			// printf("读文件: %s\n", fileAttributes->primaryFile.fileName);
			break;
		case IEC61850_FILE_CALL_GET_ATTRIBUTES:
			// printf("获取文件(或目录)'%s'的属性\n", fileAttributes->primaryFile.fileName);
			if (strcmp(fileAttributes->primaryFile.fileName, "MySecretDirectory") == 0) {
				responseCode = IEC61850_FILE_RESPONSE_ACCESS_DENIED;
			}
			break;
		case IEC61850_FILE_CALL_DELETE:
			// 设置返回值 responseCode 为 IEC61850_FILE_RESPONSE_ACCEPT 将允许删除文件
			// 设置返回值 responseCode 为 IEC61850_FILE_RESPONSE_ACCESS_DENIED 将禁止删除文件
			if (responseCode == IEC61850_FILE_RESPONSE_ACCESS_DENIED) {
				// printf("不允许删除文件'%s'\n", fileAttributes->primaryFile.fileName);
			} else if (responseCode == IEC61850_FILE_RESPONSE_ACCEPT) {
				// printf("允许删除文件'%s'\n", fileAttributes->primaryFile.fileName);
			} else {
				// printf("要删除的文件'%s'不存在\n", fileAttributes->primaryFile.fileName);
			}

			break;
		case IEC61850_FILE_CALL_SET_FILE:
			// printf("写文件。服务端下载的文件为'%s', 客户端上传的文件为'%s'\n", fileAttributes->primaryFile.fileName, fileAttributes->directoryEntries[0].fileName);
			break;
		default:
			// printf("无效的文件服务调用类别：%d\n", fileCallType);
			break;
		}
		return responseCode;
	}
	\endcode
*/
typedef IEC61850_FileResponseCode (*IEC61850_FileCallback)(void* userData, IEC61850_FileCallType fileCallType, tFileAttr* fileAttributes);

/*!	\brief	定值组操作回调。
	\details
	用于定值服务。可用于得知客户端请求了选择激活定值组、选择编辑定值组动作。
	该回调函数会在客户端请求了定值组相关操作时，在服务端被调用。

	\ingroup	ServerCallback

	\param[in]	userData	自定义用户数据
	\param[in]	sgOper		请求的定值组操作
	\param[in]	sgParam		定值组回调参数，不同的sgOper传递参数不同

	\return		返回 #SERVICE_ERROR_NO_ERROR ，将允许执行当次的定值组操作；返回 #SERVICE_ERROR_FAILED_DUE_TO_SERVER_CONSTRAIANT ，将禁止执行当次的定值组操作

	\see IEC61850_SetUserData()
*/
typedef eServiceError(*IEC61850_SettingGroupCallback)(void* userData, IEC61850_SettingGroup_Operation sgOper, void* sgParam);


/*!	\brief	用于报告FCDA更新回调。
	\details
	该回调函数会在客户端接收到报告时触发。触发机制与 #IEC61850_FCDAUpdateCallback 相同。
	该回调函数以FCDA为单位触发。
	仅适用于报告服务。

	\ingroup 	ClientCallback

	\param[in]	userData	自定义用户数据
	\param[in]	dataMap		更新的数据值的数据映射
	\param[in]	newValue	以FCDA为单位的数据值
	\param[in]	dataNum		数据数量

	\return		返回 #SERVICE_ERROR_NO_ERROR ，将允许执行当次的定值组操作；返回 #SERVICE_ERROR_FAILED_DUE_TO_SERVER_CONSTRAIANT ，将禁止执行当次的定值组操作
*/
typedef void (*IEC61850_FCDAUpdateCallback)(void* userData, const void* dataMap, const struct IEC61850_DataAttributeData* newValue, unsigned int dataNum);

/*! \brief 报告数据条目结构体 */
typedef struct IEC61850_ReportDataEntry
{
	char reference[130];				/*!< 数据对象引用路径 */
	char fc[3];							/*!< 功能约束(Functional Constraint) */
	IEC61850_DataAttributeData data;	/*!< 数据属性值 */
	U8 reasonCode;						/*!< 触发原因码 */
} IEC61850_ReportDataEntry;

/*! \brief 时间日期结构体 */
typedef struct IEC61850_TimeOfDay
{
	U32 time;	/*!< 时间戳(毫秒级) */
	U16 date;	/*!< 日期值 */
} IEC61850_TimeOfDay;

/*! \brief 客户端报告数据结构体 */
typedef struct IEC61850_ClientReportData
{
	char rptID[130];					/*!< 报告控制块标识符 */
	U16 optFlds;						/*!< 选项字段位图 */
	U32 seqNum;							/*!< 序列号 */
	IEC61850_TimeOfDay timeOfEntry;		/*!< 条目生成时间 */
	char dataset[130];					/*!< 关联的数据集引用 */
	Boolean bufOvfl;					/*!< 缓冲区溢出标志 */
	U8 entryID[8];						/*!< 条目唯一标识 */
	U32 confRev;						/*!< 配置版本号 */
	U8* inclusion;						/*!< 包含位图(需调用者释放) */
	U32 numOfInclusion;					/*!< 包含位图长度 */
	IEC61850_ReportDataEntry* entries;	/*!< 数据条目数组(需调用者释放) */
	U32 numOfEntry;						/*!< 数据条目数量 */
} IEC61850_ClientReportData;

/*! \brief 报告更新回调函数类型 */
typedef void (*IEC61850_ReportUpdateDirectCallback)(void* userData, IEC61850_ClientReportData* data);

/*! \brief GOOSE监控数据结构体 */
typedef struct IEC61850_GooseMonitorData {
	U16 appId;					/*!< 应用标识符 */
	char gocbRef[130];			/*!< GOOSE控制块引用 */
	char datasetName[130];		/*!< 关联数据集名称 */
	char gooseId[130];			/*!< GOOSE标识符 */
	U32 timeTillExpiration;		/*!< 剩余生存时间(毫秒) */
	U32 sequenceNumber;			/*!< 序列号 */
	U32 configurationRevision;	/*!< 配置版本号 */
	Boolean testMode;			/*!< 测试模式标志 */
	Boolean needsCommissioning;	/*!< 需要调试标志 */
	U32 datasetSize;			/*!< 数据集大小 */
} IEC61850_GooseMonitorData;

/*! \brief GOOSE监控回调函数类型 */
typedef void (*IEC61850_GooseMonitorCallback)(void* userData, IEC61850_GooseMonitorData* data);

/*!	\brief	文件服务属性  */
typedef struct FileServiceOption
{
	Boolean specifyFileServices;	/*!<使能标记。<br>该成员值为 TRUE 时，以下的其他成员值将被应用；<br>该成员值为 FALSE 时，将无视该结构体的所有成员值。 */
	Boolean enableGetFile;			/*!< 允许读文件标志<br>TRUE：允许；<br>FALSE：禁止。 */
	Boolean enableSetFile;			/*!< 允许写文件标志<br>TRUE：允许；<br>FALSE：禁止。 */
	Boolean enablefileDelete;		/*!< 允许删除文件标志<br>TRUE：允许；<br>FALSE：禁止。 */
	Boolean enableFileDirectory;	/*!< 允许读文件目录标志<br>TRUE：允许；<br>FALSE：禁止。  */
	Boolean enableObtainFile;		/*!< 允许文件操作标志。<br>TRUE：允许；<br>FALSE：禁止。  */
} FileServiceOption;

/*!	\brief	服务端/客户端的属性参数。
	\details
	用于为 `IEC61850_Create()` 接口创建的 IEC61850 对象配置详细属性。<br>
	具体请参照每个成员的说明。<br>
	以下是对于用户主要需要关注和设置的数据成员的说明：<br>
	- clientServerFlag：<br>
		用于标识 IEC61850 对象角色(服务端/客户端)。必须被设为 #IEC61850_SERVER 或 #IEC61850_CLIENT 。

	- Ed1_Ed2_Flag：<br>
		用于表示 IEC61850 对象版本。其值为 enum #IEC61850_Ed1_Ed2_Flag 的枚举类型。<br>
		通常指定为 #IEC61850_Edition2 。<br>
		同一环境内有通信交互关系的服务端、客户端对象，应使用相同的版本。

	- options：<br>
		用于设置 IEC61850 对象的可选参数。可以指定为 enum #IEC61850_OptionFlag 枚举值中的一个或多个选项。<br>
		指定多个选项时，选项之间需要为 “或(`|`)” 运算的关系。

	- maxServerAssociations：<br>
		服务端的最大关联数量。不设置时，默认值为 16。

	- maxClientAssociations：<br>
		客户端的最大关联数量。不设置时，默认值为 16。

	- dataMapMode：<br>
		数据映射模式。代表协议栈检索和映射模型中的数据属性所使用的资源。<br>
		该属性的值，将决定回调函数的数据属性映射参数 `dataMap` 所传入的数据类型。（无视数据映射模式的回调除外）
		- 指定为 #IEC61850_MAP_MODE_DAID ，代表属数据以数据属性ID（DAID）的方式映射，
			回调函数中的 `dataMap` 参数将为 `IEC61850_DataAttributeID*` 类型的数据属性ID；
		- 指定为 #IEC61850_MAP_MODE_SADDR ，代表属数据以短地址（sAddr）的方式映射，
			回调函数中的 `dataMap` 参数将为 `char*` 类型的短地址；
		- 指定为 #IEC61850_MAP_MODE_REFERENCE ，代表属数据以引用（Reference）的方式映射，
			回调函数中的 `dataMap` 参数将为 `char*` 类型的引用。

		不指定时，数据映射模式默认为 #IEC61850_MAP_MODE_DAID ；<br>
		不支持同时设置多种映射模式。

	- 回调函数地址：<br>
		根据回调函数属性，用户通常需要为服务端/客户端指定以下回调函数，其他回调函数可以不设置或按需设置。
		- 客户端
			- fnUpdateCallback
		- 服务端
			- fnOperateCallback
			- fnFileCallback
		- 服务端订阅端
			- fnUpdateCallback
			- fnQuestionableCallback

	\attention
	强烈建议在定义该结构体变量的当下，就对其做整体置 0 的初始化，（例如： `struct IEC61850_Parameters para = { 0 };`） ，以确保未使用到的数据成员为 0 值。<br>
	对于无需关注，或者未做设置的参数，请务必将其设置为 0 值（0 或 NULL），以避免内存中的随机值影响协议栈的正常运作。

	\see IEC61850_Create()
*/
typedef struct IEC61850_Parameters
{
	IEC61850_ClientServerFlag					clientServerFlag;			/*!< 角色标志（服务端/客户端） */
	IEC61850_Ed1_Ed2_Flag						Ed1_Ed2_Flag;				/*!< 版本标志（版本一/版本二） */
	IEC61850_LoadSGDataFlag						loadUpdatedSGDataFlag;		/*!< 定值数据初始加载方案。 \see #IEC61850_LoadSGDataFlag */
	U16											mmsTimeout;					/*!< MMS 通信超时时间。单位为毫秒。<br>未设置或设置为 0，则默认为 400 毫秒；若设置，请设置为 10 毫秒的倍数 */
	char**										authArray;					/*!< 认证信息 */
	U32											authArraySize;				/*!< 认证信息元素数量 */
	U8											serverRootSubDirDepth;		/*!< 服务端根文件夹的子目录深度 */
	S16											defaultResvTms;				/*!< 缓存报告控制块的默认保留时间(ResvTms)。单位为秒。<br>是被占用的 BRCB 实例未被客户端设置 ResvTms 时，BRCB 实例默认的 ResvTms 值。<br>不设置或设置为 0，则默认为 60 秒 */
	U32											settingGroupResvTimeout;	/*!< 定值组编辑的保留时间。单位为毫秒。<br>不设置或设置为 0，则默认为 30000 毫秒。 */
#ifndef __PARADIGM__
	unsigned int								options;					/*!< IEC61850 对象的可选参数。 \see #IEC61850_OptionFlag */
	int											cmdTermTimeout;				/*!< 控制服务的命令终止判定时间。单位为毫秒。<br>是协议栈在接收到有效的操作命令后，在评估命令终止之前等待的时间。<br>不设置或设置为 0，则默认为 10000 毫秒。 */
	unsigned int								maxServerAssociations;		/*!< 服务端的最大关联数量 */
	unsigned int								maxClientAssociations;		/*!< 客户端的最大关联数量 */
#else
	unsigned long int							options;					/*!< IEC61850 对象的可选参数。 \see #IEC61850_OptionFlag */
	unsigned long int							cmdTermTimeout;				/*!< 控制服务的命令终止超时时间(milliseconds) */
	unsigned long int							maxServerAssociations;		/*!< 服务端的最大关联数量 */
	unsigned long int							maxClientAssociations;		/*!< 客户端的最大关联数量 */
#endif
	IEC61850_DataMapMode						dataMapMode;				/*!< 数据映射模式 此处配置决定回调函数传递的参数 */
	FileServiceOption							supportedFileService;		/*!< specifyFileServices 为 true 的情况下可以设置文件操作的开关 */
	const char*									configPath;					/*!< 客户端或服务端的配置文件路径 */
	const char*									fileHandlingRootDir;		/*!< 文件处理的根目录，必须是一个以nul结尾的字符串，并且必须少于128个字符 */

	IEC61850_UpdateCallback						fnUpdateCallback;			/*!< 更新回调函数地址 */
	IEC61850_DataPointQuestionableCallback		fnQuestionableCallback;		/*!< 数据点品质可疑回调函数地址 */

	IEC61850_ControlSelectTestCallback			fnSelectTestCallback;		/*!< 选择测试回调函数地址 */
	IEC61850_ControlSelectCallback				fnSelectCallback;			/*!< 选择回调函数地址 */
	IEC61850_ControlSelectTimeoutCallback		fnSelectTimeoutCallback;	/*!< 选择超时回调函数地址 */
	IEC61850_ControlOperativeTestCallback		fnOprTestCallback;			/*!< 运行测试回调函数地址 */
	IEC61850_ControlOperateCallback				fnOperateCallback;			/*!< 操作回调函数地址 */
	IEC61850_ControlCancelCallback				fnCancelCallback;			/*!< 取消回调函数地址 */
	IEC61850_ControlCommandTerminationCallback	fnCmdTermCallback;			/*!< 命令终止回调函数地址 */

	IEC61850_ConnectionStatusCallback			fnConnectionStatusCallback; /*!< 连接状态回调函数地址 */
	IEC61850_TimeStampCallback					fnTimestampCallback;		/*!< 时间戳回调函数地址 */
	IEC61850_SettingGroupCallback				fnSettingGroupCallback;		/*!< 定值组操作回调函数地址 */
	IEC61850_FileCallback						fnFileCallback;				/*!< 文件回调函数地址 */
	//IEC61850_FilePathResolveCallback			fnFilePathResolveCallback;	/*!< 文件路径转换回调函数地址 */

	IEC61850_ReportUpdateCallback				fnReportUpdateCallback;		/*!< **禁止使用** */
	IEC61850_FCDAUpdateCallback					fnFCDAUpdateCallback;		/*!< 以FCDA为单位的更新回调函数地址 */
	IEC61850_ReportUpdateDirectCallback			fnReportUpdateDirectCallback; /*!< **禁止使用** */
	IEC61850_ReportAutoEnableSuccessCallback	fnReportAutoEnableSuccessCallback;	/*!< 报告控制块实例自动使能成功回调函数地址 */
	IEC61850_GooseMonitorCallback				fnGooseMonitorCallback;		/*!< **禁止使用** */

	IEC61850_ErrorCallback						fnErrorCallback;			/*!< 错误回调函数地址 */
	IEC61850_ReadCallback						fnReadCallback;				/*!< 读回调函数地址 */
	IEC61850_ReadMultipleCallback				fnReadMultipleCallback;		/*!< 多重读回调函数地址 */
	IEC61850_WriteCallback						fnWriteCallback;			/*!< 写回调函数地址 */
} IEC61850_Parameters;

typedef struct tOriginator
{
	U8 orCat;
	U8 orIdent[64];
} tOriginator;

/*!	\brief	控制参数。<br>用于客户端发送的控制命令。 */
typedef struct IEC61850_ControlParameters
{
	U32 timeout;				/*!< 未使用的无意义参数。**禁止使用**  */
	U8 synchroCheck;			/*!< 同期检查标志。<br>0 值代表指定控制请求中的同期检查（SynchroCheck）标志为 FALSE；<br>非 0 值代表指定控制请求中的同期检查（SynchroCheck）标志为 TRUE。 */
	U8 interlockCheck;			/*!< 互锁检查标志。<br>0 值代表指定控制请求中的同期检查（Interlock-Check）标志为 FALSE；<br>非 0 值代表指定控制请求中的同期检查（Interlock-Check）标志为 TRUE。 */
	U8 testFlag;				/*!< 测试标志。<br>0 值代表指定控制请求中的测试（Test）标志为 FALSE；<br>非 0 值代表指定控制请求中的测试（Test）标志为 TRUE。  */
	IEC61850_TimeStamp* operTm; /*< struct IEC61850_TimeStamp\* | 激活控制的时间（operTm），即，"操作" 动作的执行时刻。<br>仅在 "时间激活" 的控制流程中使用。<br>对带有 "operTm" 数据属性的控制对象请求的 "带值的操作前选择(SelectWithValue)" 命令、"时间激活的操作(TimeActivatedOperate)" 命令，以及"取消(Cancel)"控制命令，会按照 "时间激活" 的控制流程执行，需要在响应的控制请求中，为该成员指定有效的时间值，不能指定为 NULL。并且，属于同一控制序列的控制命令所附带的激活时间应该相同；<br>对不带有 "operTm" 数据属性的控制对象请求控制命令时，会按照该成员值应始终指定为 NULL。 */
	tOriginator* originator;	/*!< 控制发起者  */
	U8 ctlNum;					/*!< 控制请求编号 */
} IEC61850_ControlParameters;

/*!	\brief	日期时间。包含年、月、日、时、分、秒、微秒。  */
typedef struct IEC61850_DateTime {
	U32 tm_uSec;	/*!< 微秒。取值应为 0~999999  */
	U8 tm_sec;		/*!< 秒。取值应为 0~59  */
	U8 tm_min;		/*!< 分。取值应为 0~59 */
	U8 tm_hour;		/*!< 时。取值应为 0~23 */
	U8 tm_mday;		/*!< 日。取值应为 1~31 */
	U8 month;		/*!< 月。取值应为 1~12 */
	U16 year;		/*!< 年。取值应大于等于 1970 */
} IEC61850_DateTime;

/*!	\brief	连接信息  */
typedef struct RemoteConnection
{
	int		AAIndex;			/*!< 应用关联的索引号。<br>如果是客户端请求获取服务端的连接状态，则该值为客户端模型文件中引用的所有 ServerIED 在文件中的定义顺序的索引，值从 0 开始，最先引用的首个 ServerIED 的索引值为 0 ，若包含多个 ServerIED，则后续其他 ServerIED 的索引值按顺序依次递增 1；<br>如果是服务端请求获取客户端的连接状态，则该值为与当前服务端处于连接中状态的所有客户端的索引编号。值从 1 开始，多个连接的客户端的索引值依次递增 1，顺序为客户端与服务端关联的先后顺序。 */
	char	*iedName;			/*!< 客户端关联的服务端 IED 名称。<br>如果是客户端请求获取服务端的连接状态，则该值为客户端模型文件中引用的 ServerIED 的 IED 名称；<br>如果是服务端请求获取客户端的连接状态，则该值为 NULL。 */
	char	*IPAddress;			/*!< IP 地址。<br>如果是客户端请求获取服务端的连接状态，则该值为服务端 IED 对应接入点的 IP 地址；<br>如果是服务端请求获取客户端的连接状态，则该值为与当前服务端关联的客户端对应的 IP 地址。  */
	Boolean	bConnectionState;	/*!< 连接状态。<br>TRUE：连接中；<br>FALSE：连接断开。  */
} RemoteConnection;

/*!	\brief	连接列表 */
typedef struct ConnectionList
{
	U16		 length;				/*!< 连接数 */
	RemoteConnection *connections;	/*!< 连接信息  */
} ConnectionList;

/*!	\brief	GOOSE 控制块的基本信息  */
typedef struct GOOSEControlBlocks
{
	Boolean Enabled;						/*!< GOOSE 控制块的使能状态<br>TRUE：已使能<br>FALSE：未使能  */
	char* gocbRef;							/*!< GOOSE 控制块的引用<br>
												 该引用为 MMS 格式的引用。例如 "LDName/LLN0\$GO\$GooseCB" */
	Boolean isPublisher;					/*!< 是否为 GOOSE 发布端<br>
												 TRUE：是（发布端）<br>
												 FALSE：否（订阅端） */
	IEC61850_DataAttributeID ** daidArray;	/*!< GOOSE 控制块关联数据的 DAID 列表。<br>
												即，GOOSE 控制块所关联的数据集的数据成员中，所有配置有 DAID 的数据属性的 DAID 列表。<br>
												若有数据属性配置了 DAID，则该值为一个 IEC61850_DataAttributeID 数组的地址，数组的元素数量由 daidArraySize 成员指定<br>
												若所有数据属性都没有配置 DAID，则该值为 NULL  */
	U32 daidArraySize;						/*!< GOOSE 控制块所关联的数据集的数据成员中，配置有 DAID 的数据属性数量<br>
												若所有数据属性都没有配置 DAID，则该值为 0 */
} GOOSEControlBlocks;

/*!	\brief	数据属性信息<br>
用作 IEC61850_GetDataAttributesInfo() 接口的响应数据。<br>
客户端调用 IEC61850_GetDataAttributesInfo() 接口，响应数据中的 DAData 中不包含数据值（DAData.pvData 为 NULL），name 为数据属性的 MMS 的 FCDA 引用，例如 "CSWI0\$ST\$Pos\$stVal"<br>
服务端调用 IEC61850_GetDataAttributesInfo() 接口，响应数据中的 DAData 中会附带数据值，name 为数据属性的 ObjectName，例如 "stVal"<br>  */
typedef struct DAInfo
{
	IEC61850_DataAttributeID* DAID;		/*!< 数据属性ID（DAID） */
	IEC61850_DataAttributeData DAData;	/*!< 数据属性值 */
	char* name;							/*!< 数据属性名称 */
} DAInfo;

/*! 原因码。用于指示控制块上报或记录数据的触发原因。实际的取值，与控制块的 "触发条件" 相对应。 */
typedef enum IEC61850_ReasonCode
{
	IEC61850_RESERVED = 0x80,				/*!< 保留值（Reserved） */
	IEC61850_DATA_CHANGE = 0x40,			/*!< 数据变化（data-change） */
	IEC61850_QUALITY_CHANGE = 0x20,			/*!< 质量变化（quality-change）  */
	IEC61850_DATA_UPDATE = 0x10,			/*!< 数据更新（data-update） */
	IEC61850_INTEGRITY = 0x08,				/*!< 完整性周期（integrity）  */
	IEC61850_GENERAL_INTERROGATION = 0x04,	/*!< 总召唤（general-interrogation）  */
	IEC61850_APPLICATION_TRIGGER = 0x02,	/*!< 应用触发（application-trigger）<br>该值仅适用于日志控制块，不适用于其他类别的控制块。<br>由应用触发的日志，应该由应用保证创建规范一致的日志条目，日志的数据内容也由应用提供。   */
} IEC61850_ReasonCode;

/*! \brief 日志条目数据  */
typedef struct IEC61850_LogEntryData
{
	IEC61850_DataAttributeData  logValue;			/*!< 数据的值 */
	char DataRef[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 数据的引用 */
	char FC[FC_LEN + 1];							/*!< 功能约束 */
	IEC61850_ReasonCode reasonCode;					/*!< 日志触发原因码 */
} IEC61850_LogEntryData;

/*! \brief 日志条目  */
typedef struct IEC61850_LogEntry
{
	U8						entryId[8];			/*!< 日志条目ID */
	IEC61850_TimeStamp		entryTime;			/*!< 日志条目时间 */
	IEC61850_LogEntryData*	logEntryData;		/*!< 日志条目数据。<br>内容为 struct IEC61850_LogEntryData 的数组，元素数量由 numberOfLogEntryData 成员指定。 */
	U32						numOfLogEntryData;	/*!< logEntryData 中的日志条目数量 */
} IEC61850_LogEntry;

/*! \brief 日志条目列表  */
typedef struct IEC61850_LogEntries
{
	IEC61850_LogEntry*	entries;		/*!< 日志条目列表。<br> 内容为 struct IEC61850_LogEntry 的数组，元素数量由 numberOfEntries 成员指定 */
	U32					numOfEntries;	/*!< 日志条目数量 */
	Boolean 			moreFollows;	/*!< moreFollows */
} IEC61850_LogEntries;

/*! \brief 日志查询参数结构体 */
typedef struct LogQueryParam
{
	char LogRef[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 日志对象引用路径 */
	struct TimeOfDay* StartTime;					/*!< 查询起始时间指针 */
	struct TimeOfDay* StopTime;						/*!< 查询结束时间指针 */
	U64 entryId;									/*!< 日志条目唯一标识 */
} LogQueryParam;


/*!  \brief 日志状态值  */
typedef struct IEC61850_LogStatus
{
	IEC61850_TimeStamp OldestEntryTime;	/*!< 最老条目的条目时间 */
	IEC61850_TimeStamp NewestEntryTime;	/*!< 最新条目的条目时间 */
	U64 OldestEntry;	/*!< 最老条目的条目ID（EntryID） */
	U64 NewestEntry;	/*!< 最新条目的条目ID（EntryID） */
} IEC61850_LogStatus;

/*! \brief MMS数据类型枚举定义 */
typedef enum eMMS_TypeDescription
{
	IEC_MMS_TYPE_ARRAY = 1,				/*!< 数组类型（元素类型相同） */
	IEC_MMS_TYPE_STRUCTURE = 2,			/*!< 结构体类型（元素类型可不同） */
	IEC_MMS_TYPE_BOOLEAN = 3,			/*!< 布尔型（TRUE/FALSE） */
	IEC_MMS_TYPE_BITSTRING = 4,			/*!< 位串类型（可变长度） */
	IEC_MMS_TYPE_INTEGER = 5,			/*!< 有符号整型 */
	IEC_MMS_TYPE_UNSIGNED = 6,			/*!< 无符号整型 */
	IEC_MMS_TYPE_FLOATINGPOINT = 7,		/*!< 浮点型（IEEE754标准） */
	// 8 is Reserved					/*!< 保留值 */
	IEC_MMS_TYPE_OCTET_STRING = 9,		/*!< 八位字节串（二进制数据） */
	IEC_MMS_TYPE_VISIBLE_STRING = 10,	/*!< 可见字符串（ASCII字符） */
	IEC_MMS_TYPE_GENERALIZED_TIME = 11,	/*!< 通用时间格式 */
	IEC_MMS_TYPE_BINARY_TIME = 12,		/*!< 二进制时间格式 */
	IEC_MMS_TYPE_BCD = 13,				/*!< 二进制编码的十进制数 */
	IEC_MMS_TYPE_OBJECT_ID = 15,		/*!< MMS对象标识符 */
	IEC_MMS_TYPE_MMS_STRING = 16,		/*!< MMS专用字符串格式 */
	IEC_MMS_TYPE_UTC_TIME = 17,			/*!< UTC时间格式（IEC61850专用） */

	/* 以下为扩展的定长数据类型（非标准MMS类型） */
	IEC_MMS_TYPE_BITSTRING_FIX_LENGTH = 118,		/*!< 定长位串（已弃用） */
	IEC_MMS_TYPE_MMS_STRING_FIX_LENGTH = 119,		/*!< 定长MMS字符串 */
	IEC_MMS_TYPE_OCTET_STRING_FIX_LENGTH = 120,		/*!< 定长八位字节串 */
	IEC_MMS_TYPE_VISIBLE_STRING_FIX_LENGTH = 121,	/*!< 定长可见字符串 */
} eMMS_TypeDescription;

/*!	\brief	报告控制块关联数据批量更新的更新模式 */
typedef enum eReportBatchUpdateMode
{
	REPORT_UPDATE_AND_SEND = 0,	/*!< 更新数据并上送报告  */
	REPORT_UPDATE_NOT_SEND = 1,	/*!< 仅更新数据，不上送报告  */
} eReportBatchUpdateMode;

/*!	\brief	报告控制块所关联的数据集中的所有数据成员所对应的所有数据属性的信息。<br>
该数据是 struct IEC61850_ReportDataList 的元素成员。<br>
赋值后，用于更新报告控制块所监控数据的数据值。<br>
该数据不应手动构建，应通过 IEC61850_GetReportDataList() 接口获取该数据的列表（struct IEC61850_ReportDataList），然后给其中需要更新的数据属性元素赋值使用。 */
typedef struct IEC61850_ReportData
{
	IEC61850_DataAttributeData data;	/*!< 数据属性信息。<br>
										通过 IEC61850_GetReportDataList() 接口获取的信息中，不包括数据值。（data.pvData 为 NULL）。用于数据更新时，应手动在该成员中指定数据值（令 data.pvData 指向 data.type 对应数据类型的变量）  */
	char dataReference[OBJECT_REFERENCE_STRING_LEN+1];	/*!< 数据属性的 FCDA 引用。
														由数据集中 FCDA 的定义决定。  */
	unsigned int dataIndexInDataset;	/*!< 数据属性作为数据集成员，在数据集中的顺序索引号。<br>
										该索引号并非数据集中 FCDA 的顺序索引号，而是每个 FCDA 所对应的每个数据属性的索引号。整体的索引号顺序，由数据集中每个 FCDA 成员的定义顺序，以及每个 FCDA 所对应的每个数据属性，在模型文件中的先后定义顺序决定。  */
	void* dataDAI;	/*!< 数据属性实例信息。<br>
					在数据更新时，用于分析和定位数据属性。<br>
					该数据并非用户层使用的数据，其内容依赖于 IEC61850_GetReportDataList() 接口获取，不应由用户手动构建。  */
	IEC61850_DataAttributeID* dataDAID;	/*!< 数据属性的 DAID。<br>
										仅当模型文件中有给数据属性配置 DAID 时有效。即，调用 IEC61850_GetReportDataList() 接口所获取到的数据属性列表中，配置有 DAID 的数据属性所对应的该成员有值，否则为 NULL。  */
} IEC61850_ReportData;

/*!	\brief	报告控制块所关联的数据集中的所有数据成员所对应的所有数据属性的信息列表。<br>
该数据是由 IEC61850_GetReportDataList() 接口获取的。 给 reportDatas 成员中需要更新的一个或多个数据属性（struct IEC61850_ReportData 元素）赋值后，将作为报告数据批量更新接口 IEC61850_BatchUpdateReportDatas() 的入参使用，用于批量更新报告控制块所监控数据的数据值，以及上送数据更新的报告。<br>
reportDatas 成员中被赋值的单个数据属性（struct IEC61850_ReportData 元素），还可以作为报告数据更新接口 IEC61850_UpdateForReport() 的入参，用于更新单个数据属性值。
*/
typedef struct IEC61850_ReportDataList
{
	IEC61850_ReportData* reportDatas;	/*!< 报告控制块所关联的数据集的数据属性列表。<br>
内容为 struct IEC61850_ReportData 的数组，元素数量由 numOfRptDatas 成员指定。<br>
该数据中的元素，并非数据集中 FCDA 的数量，而是每个 FCDA 所对应的所有最子级别的 数据属性 的数量总和。（一个 FCDA 可以对应多个数据属性，具体由模型的定义决定）  */
	unsigned int numOfRptDatas;		/*!<  数据属性数量。<br> 用于指示 reportDatas 成员中包含的数据属性数量。 */
} IEC61850_ReportDataList;

/*! \brief 数据集成员数据结构 */
typedef struct IEC61850_DatasetData
{
	IEC61850_DataAttributeData data;	/*!< 数据属性值结构体 */
	char dataReference[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 数据对象引用路径 */
	unsigned int dataIndexInDataset;	/*!< 在数据集中的索引位置 */
	IEC61850_DataAttributeID* daid;		/*!< 数据属性标识符指针 */
	char* sAddr;						/*!< 短地址指针(用于优化访问) */
} IEC61850_DatasetData;

/*! \brief 控制块数据列表结构 */
typedef struct IEC61850_ControlBlockDataList
{
	IEC61850_DatasetData* datasetDatas;	/*!< 数据集成员数组指针 */
	unsigned int numOfDatas;			/*!< 数据集成员数量 */
} IEC61850_ControlBlockDataList;


/*!	\brief	带功能约束的数据引用 */
typedef struct FCDA
{
	char reference[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 数据引用  */
	char fc[FC_LEN + 1];								/*!< 功能约束  */
} FCDA;

/*!	\brief	创建数据集接口 IEC61850_CreateDataSet() 的请求数据。用于创建数据集。  */
typedef struct CreateDataSet_Request
{
	char* datasetReference;	/*!< 要创建的数据集的引用。
								对于创建永久数据集，应为 "LDName/LNName.DataSetName" 格式；
								对于创建非永久数据集，应为 "@DataSetName" 格式。 */
	FCDA* fcdaList;			/*!< 数据集的成员列表。
								内容为 FCDA 的数组，元素数量由 dataNum 指定。 */
	unsigned int dataNum;	/*!< 数据集成员的数量。用于指示 memberDatas 成员的元素数量。 */
} CreateDataSet_Request;



/*!	\brief	读数据集值 IEC61850_GetDataSetValues() 的应答数据。 */
typedef struct GetDataSetValues_Response
{
	U32  dataNum;								/*!< 数据数量  */
	IEC61850_DataAttributeData* dataAttributes;	/*!< 数据值列表<br>内容为 IEC61850_DataAttributeData 的数组，元素数量由 dataNum 成员指定  */
}GetDataSetValues_Response;

/*!	\brief	数据的引用和定义  */
typedef struct DataRefValue
{
	char* dataRef;								/*!< 数据的引用  */
	IEC61850_DataAttributeData dataAttribute;	/*!< 数据值  */
} DataRefValue;

/*\brief 服务错误列表。用于保存多个 `eServiceError` 数据。 */
typedef struct ServiceErrorList
{
	unsigned int  errNum;		/*!< 服务错误数量。<br>用于指示 `serviceErrs` 成员中包含的元素数量 */
	eServiceError* serviceErrs;	/*!< 服务错误值列表。
									应指定为一个 eServiceError 的数组的首地址，数组元素的数量应与 errNum 成员的值一致。 */
} ServiceErrorList;
/*\brief 数据值列表 */
typedef struct DataValsList
{
	U32  dataNum;								/*!< 数据数量  */
	IEC61850_DataAttributeData* dataAttributes;	/*!< 数据值列表<br>内容为 IEC61850_DataAttributeData 的数组，元素数量由 dataNum 成员指定  */
} DataValsList;


/*!	\brief	读数据集目录GetDataSetDirectory()应答数据 */
typedef struct GetDataSetDirectory_Response
{
	eServiceError serviceError;	/*!< 服务错误码 */
	U32 dataNum;				/*!< 数据数量 */
	FCDA* FCDAs;				/*!< 带功能约束的数据引用列表   内容为 struct FCDA 的数组，元素数量由 numOfFCDA 成员指定 */
}GetDataSetDirectory_Response;

/*! \brief 数据集值设置请求结构体 */
typedef struct SetDataSetValues_Request
{
	char* datasetReference;	/*!< 目标数据集引用路径(逻辑设备名+数据集名) */
	char* referenceAfter;	/*!< 插入位置参考点(用于动态数据集插入操作) */
	DataValsList value;		/*!< 待设置的值列表(包含多个数据属性值) */
} SetDataSetValues_Request;

/*! \brief 数据集值设置响应结构体 */
typedef struct SetDataSetValues_Response
{
	eServiceError serviceError;	/*!< 服务错误码 */
	ServiceErrorList result;	/*!< 详细错误信息列表(每个数据项的设置结果) */
} SetDataSetValues_Response;


/*!	\brief	读数据值的请求结构体 */
typedef struct GetDataValues_Request
{
	U32 dataNum;	/*!< 数据数量 */
	FCDA* FCDAs;	/*!< 带功能约束的数据引用列表   内容为 struct FCDA 的数组，元素数量由 numOfFCDA 成员指定 */
}GetDataValues_Request;

/*!	\brief	读数据值的请求结构体 */
typedef struct GetDataValues_Response
{
	U32  dataNum;	/*!< 数据数量  */
	IEC61850_DataAttributeData* dataAttributes;	/*!< 数据值列表<br>内容为 IEC61850_DataAttributeData 的数组，元素数量由 dataNum 成员指定  */
}GetDataValues_Response;

/*\brief 定值组控制块的值 */
typedef struct SGCBValues
{
	U8 numOfSG;					/*!< 定值的组数 [1] IMPLICIT INT8U */
	U8 actSG;					/*!< 激活的定值组号 [2] IMPLICIT INT8U */
	U8 editSG;					/*!< 编辑的定值组号 [3] IMPLICIT INT8U */
	IEC61850_TimeStamp lActTm;	/*!< 最后的激活时间 [4] IMPLICIT TimeStamp */
	U16 resvTms;				/*!< 定值组编辑的保留时间 [5] IMPLICIT INT16U OPTIONAL */
} SGCBValues;

/*\brief ACSI 服务接口 SelectActiveSG 的请求数据 */
typedef struct SelectActiveSG_Request
{
	char* sgcbReference;		/*!< 定值组控制块的引用。
								例如： "LDName/LNName\.SGCB" */
	U8 settingGroupNumber;		/*!< 要激活的定值组编号 */
}SelectActiveSG_Request;

/*\brief ACSI 服务接口 SelectEditSG 的请求数据 */
typedef struct SelectEditSG_Request
{
	char* sgcbReference;	/*!< 定值组控制块的引用。
								例如： "LDName/LNName\.SGCB"。  */
	U8 settingGroupNumber;	/*!< 要编辑的定值组编号。
								指定的定值组编号应该在定值组的数量范围内。
								指定为 0 时，代表取消编辑定值组。  */
}SelectEditSG_Request;

/*\brief ACSI 服务接口 SetEditSGValue 的请求数据 */
typedef struct SetEditSGValue_Request
{
	unsigned int dataNum;			/*!< 编辑的定值数据数量。<br> 用于指示 dataRefValues 成员中包含的定值数据值数量  */
	DataRefValue* dataRefValues;	/*!< 编辑的定值数据值列表。
									该成员应指定为一个 DataRefValue 的数组首地址，
									数组元素的数量应与 dataNum 一致，
									每个元素为每个要编辑的定值数据，其中包含定值数据的引用，以及定值数据的值  */
}SetEditSGValue_Request;

/*\brief ACSI 服务接口 SetEditSGValue 的响应数据 */
typedef struct SetEditSGValue_Response
{
	eServiceError serviceError;	/*!< 响应的 ServiceError。
									肯定响应时，值为 SERVICE_ERROR_NO_ERROR (0) ；
									否定响应时，值为其他非 0 值的 eServiceError  */
	ServiceErrorList result;	/*!< 所有编辑的定值对应响应的 eServiceError 列表。
									用于接收每个请求编辑的定值所对应的相应结果  */
}SetEditSGValue_Response;

/*\brief ACSI 服务接口 GetEditSGValue 的请求数据 */
typedef struct GetEditSGValue_Request
{
	unsigned int numOfFCDA;	/*!< 数据数量。用于指示 FCDAs 成员的元素数量  */
	FCDA* FCDAs;			/*!< 要获取的定值数据的信息列表。
								其中包括每个定值数据的引用和功能约束。
								内容为 struct FCDA 的数组，元素数量由 numOfFCDA 成员指示。   */
}GetEditSGValue_Request;

/*\brief ACSI 服务接口 GetEditSGValue 的响应数据  */
typedef struct GetEditSGValue_Response
{
	eServiceError serviceError;	/*!< 响应的 ServiceError。
								肯定响应时，值为 SERVICE_ERROR_NO_ERROR (0) ；
								否定响应时，值为其他非 0 值的 eServiceError  */
	DataValsList value;			/*!< 获取到的定值数据值的列表  */
} GetEditSGValue_Response;

/*\brief ACSI 服务接口 GetSGCBValues 的响应数据 */
typedef struct GetSGCBValues_Response
{
	eServiceError serviceError;	/*!< 响应的 ServiceError。
									肯定响应时，值为 SERVICE_ERROR_NO_ERROR (0) ；
									否定响应时，值为其他非 0 值的 eServiceError。  */
	SGCBValues sgcbValues;		/*!< 获取到的定值组控制块信息。仅在肯定响应时有效。否定响应时，值为 NULL。  */
}GetSGCBValues_Response;

/*! \brief 报告控制块可选字段配置结构体 */
typedef struct RCBOptFlds
{
	Boolean sequence_number;		/*!< 序列号使能标志(用于检测报告丢失) */
	Boolean report_time_stamp;		/*!< 时间戳使能标志(记录事件发生时间) */
	Boolean reason_for_inclusion;	/*!< 包含原因使能标志(说明数据项被包含的原因) */
	Boolean data_set_name;			/*!< 数据集名称使能标志 */
	Boolean data_reference;			/*!< 数据引用使能标志(对象引用路径) */
	Boolean buffer_overflow;		/*!< 缓冲区溢出标志 */
	Boolean entryId;				/*!< 条目ID使能标志(唯一标识报告条目) */
	Boolean conf_revision;			/*!< 配置版本使能标志 */
	Boolean segmentation;			/*!< 分段传输使能标志 */
} RCBOptFlds;

/*! \brief 报告触发条件配置结构体 */
typedef struct RCBTriggerConditions
{
	Boolean reserved;				/*!< 保留位 */
	Boolean data_change;			/*!< 数据变化触发标志 */
	Boolean quality_change;			/*!< 品质变化触发标志 */
	Boolean data_update;			/*!< 数据更新触发标志 */
	Boolean integrity;				/*!< 完整性周期触发标志 */
	Boolean general_interrogation;	/*!< 总召唤触发标志 */
} RCBTriggerConditions;

/*\brief 缓存报告控制块实例的值 */
typedef struct BRCBValues
{
	U8 rptId[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 报告控制块ID（RptID）  */
	Boolean rptEna;								/*!< 使能状态（RptEna）  */
	U8 datSet[DATASET_NAME_SIZE + 1];			/*!< 关联的数据集（DatSet）<br>
													值为数据集的引用(这里是 MMS 引用): LDName/LNName$DataSetName */
	U32 confRev;		/*!< 配置版本号（ConfRev） */
	U16 optFlds;		/*!< 可选域（OptFlds）<br>该数据为 10 bit 长度的 bit-string 类型，应通过 enum IEC61850_ReportOption 的枚举值来解析 */
	U32 bufTm;			/*!< 缓存时间（BufTm）  */
	U16 sqNum;			/*!< 时序号（SqNum）  */
	U8 trgOps;			/*!< 触发选项（TrgOps）<br>
							该数据为 6 bit 长度的 bit-string 类型<br>
							将 U8 按照 bit-string 使用，最高 6 bit 有效。各 bit 位依次代表：<br>
							bit 7：保留（reserved）。该位应始终为 0<br>
							bit 6：数据变化（data-change）<br>
							bit 5：品质变化（quality-change）<br>
							bit 4：数据更新（data-update）<br>
							bit 3：完整性周期（integrity）<br>
							bit 2：总召唤（general-interrogation）<br>
							bit 1：（无意义，不使用）<br>
							bit 0：（无意义，不使用）  */
	U32 intgPd;			/*!< 完整性周期（IntgPd）,单位为毫秒  */
	Boolean gi;			/*!< 总召唤状态（GI）  */
	U8 owner[64];		/*!< 实例拥有者（Owner）  */
	Boolean purgeBuf;	/*!< 清除缓存状态（PurgeBuf）  */
	U8 entryId[8];		/*!< 条目ID（EntryID）  */
	U8 timeOfEntry[6];	/*!< 条目时间（TimeOfEntry）  */
	U16 resvTms;		/*!< 保留时间（ResvTms）。是否支持该属性，取决于服务端 IED 的配置。  */
}BRCBValues;

/*\brief 非缓存报告控制块的值。 */
typedef struct URCBValues
{
	U8 rptId[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 报告控制块ID（RptID） */
	Boolean rptEna;								/*!< 使能状态（RptEna） */
	U8 datSet[DATASET_NAME_SIZE + 1];			/*!< 关联的数据集（DatSet）<br>
													值为数据集的引用（这里是 MMS 引用）：LDName/LNName$DataSetName */
	U32 confRev;	/*!< 配置版本号（ConfRev）  */
	U16 optFlds;	/*!< 可选域（OptFlds）<br>
						该数据为 10 bit 长度的 bit-string 类型<br>
						应通过 enum IEC61850_ReportOption 的枚举值来解析<br>  */
	U32 bufTm;		/*!< 缓存时间（BufTm）  */
	U16 sqNum;		/*!< 时序号（SqNum）  */
	U8 trgOps;		/*!< 触发选项（TrgOps）<br>
						该数据为 6 bit 长度的 bit-string 类型<br>
						将 U8 按照 bit-string 使用，最高 6 bit 有效。各 bit 位依次代表：<br>
						bit 7：保留（reserved）。该位应始终为 0<br>
						bit 6：数据变化（data-change）<br>
						bit 5：品质变化（quality-change）<br>
						bit 4：数据更新（data-update）<br>
						bit 3：完整性周期（integrity）<br>
						bit 2：总召唤（general-interrogation）<br>
						bit 1：（无意义，不使用）<br>
						bit 0：（无意义，不使用）<br>  */
	U32 intgPd;		/*!< 完整性周期（IntgPd）<br> 单位为毫秒  */
	Boolean gi;		/*!< 总召唤状态（GI）  */
	U8 owner[64];	/*!< 实例拥有者（Owner）  */
	Boolean resv;	/*!< 保留状态（Resv）  */
}URCBValues;

/*! \brief 报告控制块值结构体 */
typedef struct RCBValues
{
	U8 rptId[OBJECT_REFERENCE_STRING_LEN + 1];  /*!< 报告ID(逻辑设备名+报告控制块名) */
	Boolean bufferFlag;							/*!< 缓冲标志(TRUE-带缓冲报告,FALSE-非缓冲报告) */
	Boolean rptEna;								/*!< 报告使能标志(TRUE-激活报告功能) */
	U8 datSet[DATASET_NAME_SIZE + 1];			/*!< 关联的数据集名称 */
	U32 confRev;								/*!< 配置版本号(数据集修改时自动递增) */
	U16 optFlds;								/*!< 可选字段位图(对应RCBOptFlds结构) */
	U32 bufTm;									/*!< 缓冲时间(单位ms,0表示立即发送) */
	U16 sqNum;									/*!< 序列号(每次报告递增) */
	U8 trgOps;									/*!< 触发操作位图(对应RCBTriggerConditions) */
	U32 intgPd;									/*!< 完整性周期(单位ms,0表示不启用) */
	Boolean gi;									/*!< 总召唤标志(TRUE-触发总召唤) */
	U8 owner[64];								/*!< 所有者标识(客户端应用标识) */
	Boolean purgeBuf;							/*!< 清除缓冲区标志(TRUE-清除未发送报告) */
	U8 entryId[8];								/*!< 条目ID(唯一标识报告条目) */
	IEC61850_TimeStamp timeOfEntry;				/*!< 条目时间戳(报告生成时间) */
	U16 resvTms;								/*!< 保留时间(单位ms)适用于缓存报告控制块 */
	Boolean resv;								/*!< 保留标志,适用于非缓存报告控制块 */
} RCBValues;


/*\brief 请求设置的 BRCB 实例的值<br>
reference 用于指定被设置的 BRCB 实例，其他成员用于指定要被设置的 BRCB 实例的值。 <br>
应至少请求设置一个属性。不需要设置的属性，指定其值为 NULL 即可 */
typedef struct tSetBRCBValues
{
	char* reference;	/*!< 请求设置的 BRCB 实例的引用<br>例如：LDName/LNName.brcbName01  */
	char* rptId;		/*!< 请求设置的报告控制块实例的ID<br>该属性仅能在 rptEna = FALSE 时设置  */
	Boolean* rptEna;	/*!< 请求设置的报告控制块实例的使能状态。（RptEna）<br>TRUE：使能<br> FALSE：取消使能  */
	U8*   datSet;		/*!< 请求设置的报告控制块实例关联的数据集（DatSet）<br>
							值为数据集的引用（这里是 MMS 引用）：LDName/LNName$DataSetName<br>
							该属性仅能在 rptEna = FALSE 时设置<br>  */
	U16*  optFlds;		/*!< 请求设置的报告控制块实例的可选域<br>
							该数据为 10 bit 长度的 bit-string 类型，应通过 enum IEC61850_ReportOption 的枚举值来设置<br>
							设置对应意义的 bit 位为 1 或 0，代表 启用 或 不启用 对应的可选域<br>
							该属性仅能在 rptEna = FALSE 时设置  */
	U32*  bufTm;		/*!< 请求设置的报告控制块实例的缓存时间
							该属性仅能在 rptEna = FALSE 时设置  */
	U8*   trgOps;		/*!< 请求设置的报告控制块实例的触发选项<br>
							设置对应意义的 bit 位为 1 或 0，代表 启用 或 不启用 对应的触发选项<br>
							该属性仅能在 rptEna = FALSE 时设置<br>
							该数据为 6 bit 长度的 bit-string 类型<br>
							将 U8 按照 bit-string 使用，最高 6 bit 有效。各 bit 位依次代表：<br>
							bit 7：保留（reserved）。该位应始终为 0<br>
							bit 6：数据变化（data-change）<br>
							bit 5：品质变化（quality-change）<br>
							bit 4：数据更新（data-update）<br>
							bit 3：完整性周期（integrity）<br>
							bit 2：总召唤（general-interrogation）<br>
							bit 1：（无意义，不使用）<br>
							bit 0：（无意义，不使用）  */
	U32*  intgPd;		/*!< 请求设置的报告控制块实例的完整性周期<br>
							该值的单位是毫秒<br>
							该属性仅能在 rptEna = FALSE 时设置  */
	Boolean* gi;		/*!< 请求报告控制块的总召唤<br>
							请求设置该值为 TRUE，用于触发总召唤报告<br>
							(但前提是当前报告控制块实例启用了 gi 的触发选项)<br>
							该属性仅能在 rptEna = TRUE 时设置<br>
							仅应请求设置该值为 TRUE，不应请求设置该值为 FALSE  */
	Boolean* purgeBuf;	/*!< 请求清除报告控制块实例的缓存<br>
							请求设置该值为 TRUE，用于清除缓存的报告<br>
							仅应请求设置该值为 TRUE，不应请求设置该值为 FALSE<br>  */
	U8*   entryId;		/*!< 请求设置的报告控制块实例的条目ID<br>
							设置该属性仅能在 rptEna = FALSE 时设置<br>
							设置为 0 值，代表使能后将从缓存的首个条目开始上送报告<br>
							设置为指定的条目ID，代表使能后将从指定的缓存条目开始上送报告  */
	U16*  resvTms;		/*!< 请求设置的报告控制块实例的保留时间<br>
							该值的单位是秒<br>
							该属性仅能在 rptEna = FALSE 时设置<br>
							若服务端 IED 不支持该属性，则不能设置该属性  */
}tSetBRCBValues;

/*\brief 请求设置的 URCB 实例的值。<br>
reference 用于指定被设置的 URCB 实例，其他成员用于指定要被设置的 URCB 实例的值。 <br>
应至少请求设置一个属性。不需要设置的属性，指定其值为 NULL 即可。  */
typedef struct tSetURCBValues
{
	char* reference;	/*!< 请求设置的 URCB 实例的引用。<br>例如：LDName/LNName.urcbName01。  */
	char* rptId;		/*!< 请求设置的报告控制块实例的ID。<br>该属性仅能在 rptEna = FALSE 时设置。  */
	Boolean* rptEna;	/*!< 请求设置的报告控制块实例的使能状态。（RptEna）<br>TRUE：使能。<br>FALSE：取消使能。  */
	U8*   datSet;		/*!< 请求设置的报告控制块实例关联的数据集（DatSet）。<br>值为数据集的引用（这里是 MMS 引用）：LDName/LNName$DataSetName。<br>该属性仅能在 rptEna = FALSE 时设置。  */
	U16*  optFlds;		/*!< 请求设置的报告控制块实例的可选域。<br>
							该数据为 10 bit 长度的 bit-string 类型，应通过 enum IEC61850_ReportOption 的枚举值来设置。<br>
							设置对应意义的 bit 位为 1 或 0，代表 启用 或 不启用 对应的可选域。<br>
							该属性仅能在 rptEna = FALSE 时设置。  */
	U32*  bufTm;		/*!< 请求设置的报告控制块的缓存时间。<br>该属性仅能在 rptEna = FALSE 时设置。  */
	U8*   trgOps;		/*!< 请求设置的报告控制块实例的触发条件。<br>
							设置对应意义的 bit 位为 1 或 0，代表 启用 或 不启用 对应的触发条件。<br>
							该属性仅能在 rptEna = FALSE 时设置。<br>
							该数据为 6 bit 长度的 bit-string 类型。<br>
							将 U8 按照 bit-string 使用，最高 6 bit 有效。各 bit 位依次代表：<br>
							bit 7：保留（reserved）。该位应始终为 0<br>
							bit 6：数据变化（data-change）<br>
							bit 5：品质变化（quality-change）<br>
							bit 4：数据更新（data-update）<br>
							bit 3：完整性周期（integrity）<br>
							bit 2：总召唤（general-interrogation）<br>
							bit 1：（无意义，不使用）<br>
							bit 0：（无意义，不使用）  */
	U32*  intgPd;		/*!< 请求设置的报告控制块实例的完整性周期。<br>
							该值的单位是毫秒。<br>
							该属性仅能在 rptEna = FALSE 时设置。  */
	Boolean* gi;		/*!< 请求报告控制块实例的总召唤。<br>
							请求设置该值为 TRUE，用于触发总召唤报告。<br>
							（但前提是当前报告控制块实例启用了 gi 的触发选项）<br>
							该属性仅能在 rptEna = TRUE 时设置。<br>
							仅应请求设置该值为 TRUE，不应请求设置该值为 FALSE。<br>  */
	Boolean* resv;		/*!< 请求设置的报告控制块实例的保留状态。<br>
							TRUE：被客户端保留占用。<br>
							FALSE：未被客户端保留占用。<br>
							该属性仅能在 rptEna = FALSE 时设置。<br>  */
}tSetURCBValues;

/*\brief 请求设置的 BRCB 的值所对应的设置结果<br>
		每个成员一一对应设置报告控制块对应属性的值所对应响应的 ServiceError。 <br>
		设置成功的属性，其对应成员的值为 SERVICE_ERROR_NO_ERROR (0) <br>
		设置失败的属性，其对应成员的值为其他非 0 值的 eServiceError  */
typedef struct tSetBRCBErrors
{
	eServiceError setRptIDError;	/*!< 设置报告控制块ID（RptID）的响应结果  */
	eServiceError setRptEnaError;	/*!< 设置报告控制块使能状态（RptEna）的响应结果  */
	eServiceError setDataSetError;	/*!< 设置报告控制块关联的数据集（DatSet）的响应结果  */
	eServiceError setOptFldsError;	/*!< 设置报告控制块可选域（OptFlds）的响应结果  */
	eServiceError setBufTmError;	/*!< 设置报告控制块缓存时间（BufTm）的响应结果  */
	eServiceError setTrgOpsError;	/*!< 设置报告控制块触发选项（TrgOps）的响应结果  */
	eServiceError setIntgPdError;	/*!< 设置报告控制块完整性周期（IntgPd）的响应结果  */
	eServiceError setGIError;		/*!< 设置报告控制块总召唤状态（GI）的响应结果  */
	eServiceError setPurgeBufError;	/*!< 设置报告控制块清除缓存状态（PurgeBuf）的响应结果  */
	eServiceError setEntryIDError;	/*!< 设置报告控制块条目ID（EntryID）的响应结果  */
	eServiceError setResvTmsError;	/*!< 设置报告控制块保留时间（ResvTms）的响应结果  */
}tSetBRCBErrors;

/*\brief 请求设置的 URCB 的值所对应的设置结果。<br>
每个成员一一对应设置报告控制块对应属性的值所对应响应的 ServiceError。 <br>
设置成功的属性，其对应成员的值为 SERVICE_ERROR_NO_ERROR (0) ； 设置失败的属性，其对应成员的值为其他非 0 值的 eServiceError  */
typedef struct tSetURCBErrors
{
	eServiceError setRptIDError;	/*!< 设置报告控制块ID（RptID）的响应结果  */
	eServiceError setRptEnaError;	/*!< 设置报告控制块使能状态（RptEna）的响应结果  */
	eServiceError setDataSetError;	/*!< 设置报告控制块关联的数据集（DatSet）的响应结果  */
	eServiceError setOptFldsError;	/*!< 设置报告控制块可选域（OptFlds）的响应结果  */
	eServiceError setBufTmError;	/*!< 设置报告控制块缓存时间（BufTm）的响应结果  */
	eServiceError setTrgOpsError;	/*!< 设置报告控制块触发选项（TrgOps）的响应结果  */
	eServiceError setIntgPdError;	/*!< 设置报告控制块完整性周期（IntgPd）的响应结果  */
	eServiceError setGIError;		/*!< 设置报告控制块总召唤状态（GI）的响应结果  */
	eServiceError setResvError;		/*!< 设置报告控制块保留状态（Resv）的响应结果  */
}tSetURCBErrors;

/*\brief 读缓存报告控制块值的响应数据 */
typedef struct GetBRCBValues_Response
{
	eServiceError serviceError;	/*!< 响应的 eServiceError<br>
									肯定响应时，值为 #SERVICE_ERROR_NO_ERROR (0)<br>
									否定响应时，值为其他非 0 值的 eServiceError  */
	BRCBValues	rcbVal;			/*!< 缓存报告控制块实例的值  */
} GetBRCBValues_Response;

/*\brief 设置缓存报告控制块值的请求数据<br>用于 IEC61850_SetBRCBValues() 接口的请求参数 */
typedef struct SetBRCBValues_Request
{
	unsigned int  numOfRptCB;		/*!< 请求设置的缓存报告控制块实例的数量。
										用于指示 brcbValsList 成员中的元素数量  */
	tSetBRCBValues* brcbValsList;	/*!< 请求设置的缓存报告控制块值的列表。<br>
										 应指定为一个 tSetBRCBValues 数组的地址，<br>
										 数组元素的数量应与 numOfRptCB 一致，<br>
										 每个元素对应每个请求设置的 BRCB 实例的值  */
}SetBRCBValues_Request;

/*\brief 设置缓存报告控制块值的响应结果数据<br>用于 IEC61850_SetBRCBValues() 接口的响应参数 */
typedef struct SetBRCBValues_Response
{
	eServiceError serviceError;		/*!< 响应的 eServiceError<br>
										肯定响应时，值为 #SERVICE_ERROR_NO_ERROR (0) <br>
										否定响应时，值为其他非 0 值的 eServiceError */
	unsigned int  numOfRptCB;		/*!< 响应的设置缓存报告控制块值的结果数量<br>
										用于指示 setRCBErrsList 成员中的响应结果元素数量<br>
										该数量必须与接口 IEC61850_SetBRCBValues() 的 SetBRCBValues_Request* request 参数中请求设置的报告控制块实例数量一致  */
	tSetBRCBErrors* setRCBErrsList;	/*!< 响应的设置缓存报告控制块值的结果列表<br>
										应指定为一个 tSetBRCBErrors 数组的地址<br>
										数组元素的数量应与 numOfRptCB 一致<br>
										每个元素用于接收每个请求设置的 BRCB 实例所对应的响应结果  */
}SetBRCBValues_Response;

/*\brief 读非缓存报告控制块值的响应数据 */
typedef struct GetURCBValues_Response
{
	eServiceError serviceError;	/*!< 响应的 eServiceError<br>
									肯定响应时，值为 SERVICE_ERROR_NO_ERROR (0)<br>
									否定响应时，值为其他非 0 值的 eServiceError  */
	URCBValues rcbVal;			/*!< 非缓存报告控制块的值  */
}GetURCBValues_Response;

/*\brief 设置非缓存报告控制块值的请求数据。<br>用于 IEC61850_SetURCBValues() 接口的请求参数。 */
typedef struct SetURCBValues_Request
{
	unsigned int  numOfRptCB;		/*!< 请求设置的非缓存报告控制块实例的数量<br>
										 用于指示 urcbValsList 成员中的元素数量  */
	tSetURCBValues* urcbValsList;	/*!< 请求设置的非缓存报告控制块值的列表<br>
										应指定为一个 tSetURCBValues 数组的地址，数组元素的数量应与 numOfRptCB 一致，每个元素对应每个请求设置的 URCB 实例的值。 */
}SetURCBValues_Request;

/*\brief 设置非缓存报告控制块值的响应结果数据。用于 IEC61850_SetURCBValues() 接口的响应参数。 */
typedef struct
{
	eServiceError serviceError;		/*!< 响应的 ServiceError。肯定响应时，值为 SERVICE_ERROR_NO_ERROR (0) ；
										否定响应时，值为其他非 0 值的 eServiceError。  */
	unsigned int  numOfRptCB;		/*!< 响应的设置非缓存报告控制块值的结果数量。
										用于指示 setRCBErrsList 成员中的响应结果元素数量。
										该数量必须与接口 IEC61850_SetURCBValues() 的 SetURCBValues_Request* request 参数中请求设置的报告控制块实例数量一致。  */
	tSetURCBErrors* setRCBErrsList;	/*!< 响应的设置非缓存报告控制块值的结果列表。
										应指定为一个 tSetURCBErrors 数组的地址，
										数组元素的数量应与 numOfRptCB 一致，
										每个元素用于接收每个请求设置的 BRCB 实例所对应的响应结果。  */
}SetURCBValues_Response;

/*! \brief 控制状态枚举(定义设备控制流程状态机) */
typedef enum eControlState
{
	CONTROL_STATE_DISABLED,					/*!< 禁用状态(控制功能不可用) */
	CONTROL_STATE_UNSELECTED,				/*!< 未选中状态(设备待命但未激活) */
	CONTROL_STATE_READY,					/*!< 就绪状态(可接收控制指令) */
	CONTROL_STATE_WAIT_FOR_CHANGE,			/*!< 等待状态变更(执行中间状态) */
	CONTROL_STATE_WAIT_FOR_ACTIVATION_TIME,	/*!< 等待激活时间(延时控制状态) */
} eControlState;

/*! \brief 控制信息结构体(记录控制过程元数据) */
typedef struct ControlInfo
{
	int				currentState;	/*!< 当前控制状态(对应eControlState枚举) */
	U32				stVal;			/*!< 状态值(设备当前状态编码) */
	U8				stValType;		/*!< 状态值类型(标识stVal的编码格式) */
	U8				stValSize;		/*!< 状态值字节长度 */
	U32				ctlVal;			/*!< 控制值(待执行的控制指令编码) */
	U8				ctValType;		/*!< 控制值类型(标识ctlVal的编码格式) */
	U8				ctlValSize;		/*!< 控制值字节长度 */
	unsigned char	OrCat;			/*!< 控制源类别(标识操作者类型) */
	unsigned char	OrIdent[CONTROL_ORIGIN_IDENT_SIZE];	/*!< 控制源标识(操作者ID) */
	unsigned char	OrIdentSize;	/*!< 控制源标识实际长度 */
	U8				controlNumber;	/*!< 控制序列号(防重复操作) */
	unsigned char	Time[CONTROL_TIME_SIZE];	/*!< 控制时间戳(YYYYMMDDhhmmss格式) */
	unsigned char	Test;			/*!< 测试模式标志位 */
	unsigned char	Check;			/*!< 校验标志位 */
	U8				operTime[CONTROL_TIME_SIZE];	/*!< 操作执行时间(预留字段) */
} ControlInfo;


/*!	\brief	数据携带对应q和t的结构体数据  */
typedef struct IEC61850_DataAttributeDataQT
{
	IEC61850_DataAttributeData	dataVal;		/*!< 数据值 */
	tIEC61850Quality* q;				/*!< 质量 */
	IEC61850_TimeStamp* t;				/*!< 时间 */
} IEC61850_DataAttributeDataQT;

/*! \brief 关联参数结构体(用于ACSE关联建立) */
typedef struct IEC61850_AssociationParameters
{
	char calledAPTitle[32];		/*!< 被叫应用进程标题(最大31字符+结束符) */
	S32 calledAEQualifier;		/*!< 被叫应用实体限定符 */
	U32 calledPSelect;			/*!< 被叫表示层选择器(OSI模型第6层) */
	U16 calledSSelect;			/*!< 被叫会话层选择器(OSI模型第5层) */
	U16 calledTSelect;			/*!< 被叫传输层选择器(OSI模型第4层) */

	char callingAPTitle[32];	/*!< 主叫应用进程标题(最大31字符+结束符) */
	S32 callingAEQualifier;		/*!< 主叫应用实体限定符 */
	U32 callingPSelect;			/*!< 主叫表示层选择器 */
	U16 callingSSelect;			/*!< 主叫会话层选择器 */
	U16 callingTSelect;			/*!< 主叫传输层选择器 */

	char IPAddress[16];			/*!< 服务器IP地址(IPv4格式) */
	U16 port;					/*!< 服务器TCP端口号(默认102) */
	char* authPassword;			/*!< ACSE认证密码指针(未使用时置NULL) */
} IEC61850_AssociationParameters;

/*! \brief 模型查询层级枚举(MMS目录服务) */
typedef enum IEC61850_QueryLevel
{
	QUERY_LEVEL_SERVER_DIR = 1,	/*!< 服务器级查询(获取LD列表) */
	QUERY_LEVEL_LD_DIR = 2,		/*!< 逻辑设备级查询(获取LN列表) */
	QUERY_LEVEL_LN_DIR = 3,		/*!< 逻辑节点级查询(获取数据对象) */
	QUERY_LEVEL_DATASET = 4,	/*!< 数据集级查询 */
	QUERY_LEVEL_LOG = 5,		/*!< 日志服务查询 */
} IEC61850_QueryLevel;

/*! \brief 数据类型描述结构体 */
typedef struct IEC61850_DataTypeInfo {
	enum eMMS_TypeDescription type;	/*!< MMS类型描述(基本/结构/数组等) */
	char name[256];					/*!< 类型名称(含命名空间路径) */
	U32 size;						/*!< 类型字节大小 */
	U32 sizeExponent;				/*!< 浮点数指数位宽(仅FLOAT类型有效) */
	U32 numOfElements;				/*!< 元素数量(数组/结构体类型使用) */
	struct IEC61850_DataTypeInfo* elements; /*!< 子元素指针(复合类型使用) */
} IEC61850_DataTypeInfo;

/*! \brief 远程控制参数结构体 */
typedef struct IEC61850_ControlRemote
{
	char domain[129];			/*!< 控制域标识(逻辑设备名) */
	char itemName[129];			/*!< 控制项名称(数据属性名) */
	char reference[129];		/*!< 完整对象引用路径 */
	char ctlType;				/*!< 控制值类型(对应MMS数据类型) */
	unsigned int ctlSize;		/*!< 控制值字节大小 */
	unsigned int ctlNum;		/*!< 控制序列号(SBO模式下使用) */
	unsigned char orCat;		/*!< 控制源类别(操作者类型) */
	char orIdent[BYTES_64];		/*!< 控制源标识(64字节OCTET STRING) */
	unsigned char orIdentSize;	/*!< 实际使用的标识字节数 */
} IEC61850_ControlRemote;

/*! \brief 报告控制块结构体 */
typedef struct IEC61850_ReportControlBlock
{
	char* name;						/*!< 控制块实例名称 */
	char* datasetName;				/*!< 关联数据集名称 */
	void* dataset;					/*!< 数据集对象指针 */

	void* CBID;						/*!< 控制块标识符 */

	unsigned int intgPeriod;		/*!< 完整性报告周期(毫秒) */
	char* rptId;					/*!< 报告标识符 */
	unsigned int confRev;			/*!< 配置版本号 */
	Boolean bBuffered;				/*!< 缓冲模式标志 */
	unsigned int bufTime;			/*!< 缓冲时间(毫秒) */
	Boolean bIndexed;				/*!< 索引报告模式标志 */

	char* owner;					/*!< 所有者属性值 */

	void* reportEnabledClients;		/*!< 启用报告的客户端数组 */
	unsigned int numOfReportEnabledClients; /*!< 启用客户端数量 */

	/* 可选字段标志位 */
	Boolean bSeqNum;		/*!< 包含序列号 */
	Boolean bTimeStamp;		/*!< 包含时间戳 */
	Boolean bDataSet;		/*!< 包含数据集引用 */
	Boolean bReasonCode;	/*!< 包含原因码 */
	Boolean bDataRef;		/*!< 包含数据引用 */
	Boolean bEntryID;		/*!< 包含条目ID */
	Boolean bConfigRef;		/*!< 包含配置引用 */
	Boolean bBufOvfl;		/*!< 包含缓冲区溢出标志 */

	/* 触发条件标志位 */
	Boolean bDataChange;		/*!< 数据变化触发 */
	Boolean bQualityChange;		/*!< 品质变化触发 */
	Boolean bDataUpdate;		/*!< 数据更新触发 */
	Boolean bIntegrityPeriod;	/*!< 完整性周期触发 */
	Boolean bGI;				/*!< 总召唤触发 */

	void* reportInstances;					/*!< 报告实例数组 */
	unsigned int maxNumOfReportInstances;	/*!< 最大报告实例数 */
} IEC61850_ReportControlBlock;



/*!  \brief 数据属性列表 */
typedef struct IEC61850_DataAttributeValues
{
	U32 length;						/*!< 数据数量 */
	DataRefValue* dataRefValueList;	/*!< 数据的引用和值。<br>内容为 `struct DataRefValue` 的数组，元素数量由 `length` 成员指定 */
} IEC61850_DataAttributeValues;

/*!  \brief 数据定义 */
typedef struct DataDefinition
{
	IEC61850_DataType type;						/*!< 基本数据类型 */
	int arraySize;								/*!< 数组元素数量。<br>仅在数据类型 `eType` 为数组 `DATA_TYPE_ARRAY` 时为数组元素数量，否则为 0 */
	int structSize;								/*!< 结构体成员数量。<br>仅在数据类型 `eType` 为结构体 `DATA_TYPE_STRUCTURE` 时，该值为结构体成员数量，否则为 0 */
	struct DataDefinition* arrayDefinition;		/*!< 数组元素数据的定义。<br>需要进一步解析。 */
	struct StructDefinition* structDefinition;	/*!< 结构体成员数据的定义<br>需要基于 `structSize` 指定的数量继续遍历解析 */
	unsigned int stringSize;					/*!< 字符串长度。<br>仅在数据类型 `eType` 为字符串类型（`#DATA_TYPE_BIT_STRING` \|  `#DATA_TYPE_OCTET_STRING` \| `#DATA_TYPE_VISIBLE_STRING` \| `#DATA_TYPE_UNICODE_STRING` \|时，该值为字符串长度值，否则为 0 */
} DataDefinition;

/*!  \brief 结构体成员的定义 */
typedef struct StructDefinition
{
	char name[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 结构体成员名称 */
	char FC[3];									/*!< 结构体成员的功能约束 */
	DataDefinition definition;					/*!< 结构体成员的数据定义 */
} StructDefinition;

/*!	\brief	数据定义。包含数据引用，以及公共数据类类型。 */
typedef struct DataRefDefinition
{
	char dataRef[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 数据的引用 */
	char sCDC[CDC_STRING_LEN];						/*!< 公共数据类 */
	DataDefinition definition;						/*!< 数据定义 */
} DataRefDefinition;

/*!	\brief	数据定义列表 */
typedef struct DataDefinitions
{
	U32 length;									/*!< 数据数量 */
	DataRefDefinition* dataRefDefinitionList;	/*!< 数据定义列表<br>内容为 `struct DataRefDefinition` 的数组，元素数量由 `length` 成员指定 */
} DataDefinitions;
/*\brief 日志控制块的值 */
typedef struct LCBValues
{
	Boolean logEna;	/*!< 使能标记  TRUE：使能   FALSE：未使能 */
	char datSet[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 控制块关联的数据集引用 */
	char trgOps;	/*!< 触发条件。
						触发条件的定义为 BIT STRING(SIZE(6))。
						取其最高的 6 个 bit 位来使用，
						最高位记为 bit 0，各 bit 位的含义依次为：
						bit 0：保留（reserved）
						bit 1：数据变化触发（data-change）
						bit 2：质量变化触发（quality-change）
						bit 3：数据更新触发（data-update）
						bit 4：完整性周期触发（integrity）
						bit 5：总召唤触发（general-interrogation） */
	U32 intgPd;		/*!< 完整性周期 */
	char logRef[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 存储日志的引用 */
	char optFlds;	/*!< 可选域。
						日志控制块的可选域为 BIT STRING(SIZE(1))，
						内容为 "包含原因（reason-for-inclusion）" */
	U32 bufTm;		/*!< 缓存时间 */
} LCBValues;

/* \brief GOOSE控制块的值 */
typedef struct GoCBValues
{
	Boolean goEna;	/*!<  使能标记  TRUE：使能		FALSE：未使能 */
	char goID[VISIBLE_STRING_129_LEN + 1];	/*!< GOOSE控制块的ID */
	char datSet[OBJECT_REFERENCE_STRING_LEN + 1]; /*!< 控制块关联的数据集引用 */
	U32 confRev;	/*!< 配置版本号 */
	Boolean ndsCom;	/*!< "需要重新配置" 标记 */
	U8 addr[6];		/*!< 地址 */
	U8 priority;	/*!< 优先级 */
	U16 vid;		/*!< VLAN ID */
	U16 appid;		/*!< 应用ID */
} GoCBValues;

/*! \brief 采样模式枚举(定义信号采集的计量方式) */
typedef enum SampleMode
{
	SMP_MOD_SAMPLES_PER_NOMINAL_PERIOD = 0,	/*!< 每标称周期采样点数模式(周期信号专用) */
	SMP_MOD_SAMPLES_PER_SECOND = 1,			/*!< 每秒采样点数模式(固定采样率) */
	SMP_MOD_SECONDS_PER_SAMPLE = 2			/*!< 每采样点间隔秒数模式(可变采样间隔) */
} SampleMode;


/*\brief 多播采样值控制块的值 */
typedef struct MSVCBValues
{
	Boolean svEna;	/*!< 使能标记  TRUE：使能，FALSE：未使能 */
	char msvID[VISIBLE_STRING_129_LEN + 1];			/*!< 多播采样值控制块的ID */
	char datSet[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 控制块关联的数据集引用 */
	U32 confRev;	/*!< 配置版本号 */
	S8 smpMod;		/*!< 采样模式。
						0：samples-per-nominal-period
						1：samples-per-second
						2：seconds-per-sample */
	U16 smpRate;	/*!< 采样率 */
	char optFlds;	/*!< 可选域。
						多播采样值控制块的可选域定义为 BIT STRING(SIZE(5))
						取其最高的 5 个 bit 位来使用，
						最高位记为 bit 0，各 bit 位的含义依次为：
						bit 0：刷新时间（refresh-time）
						bit 1：保留（reserved）
						bit 2：采样率（sample-rate）
						bit 3：数据集名称（data-set-name）
						bit 4：安全（security） */
	U8 addr[6];		/*!< 地址 */
	U8 priority;	/*!< 优先级 */
	U16 vid;		/*!< VLAN ID */
	U16 appid;		/*!< 应用ID */
} MSVCBValues;

/*\brief ACSI 服务接口 GetAllCBValues 的响应数据。控制块值列表。 */
typedef struct GetAllCBValsReturn
{
	U32	numOfCB;				/*!< 控制块数量。代表响应的控制块数量 */

	RCBValues* brcbValues;		/*!< 缓存报告控制块列表。
									请求的 ACSIClass 为 BRCB 时，该值有效，否则为 NULL。
									有效时，RCBValues 的数量由 numOfCB 指示。 */
	RCBValues* urcbValues;		/*!< 非缓存报告控制块列表。
									请求的 ACSIClass 为 URCB 时，该值有效，否则为 NULL。
									有效时，RCBValues 的数量由 numOfCB 指示。 */
	SGCBValues* sgcbValues;		/*!< 定值组控制块列表。
									请求的 ACSIClass 为 SGCB 时，该值有效，否则为 NULL。
									有效时，SGCBValues 的数量由 numOfCB 指示。 */
	LCBValues* lcbValues;		/*!< 日志控制块列表。
									请求的 ACSIClass 为 LCB 时，该值有效，否则为 NULL。
									有效时，LCBValues 的数量由 numOfCB 指示。 */
	GoCBValues* goCBValues;		/*!< GOOSE控制块列表。
									请求的 ACSIClass 为 GoCB 时，该值有效，否则为 NULL。
									有效时，GoCBValues 的数量由 numOfCB 指示。 */
	MSVCBValues* svCBValues;	/*!< 多播采样值控制块列表。
									请求的 ACSIClass 为 MSVCB 时，该值有效，否则为 NULL。
									有效时，MSVCBValues 的数量由 numOfCB 指示。 */
} GetAllCBValsReturn;

/*!\brief ACSI 服务接口 GetServerDirectory 的请求数据 */
typedef struct GetServerDirectory_Request
{
	int objectClass;		/*!< 对象类别。该值应始终指定为 1 (代表 logical-device)，不应指定为其他值。 */
	char* referenceAfter;	/*!< 对象引用。代表请求应响应该对象之后的对象。 */
}GetServerDirectory_Request;

/*!\brief ACSI 服务接口 GetServerDirectory 的响应数据 */
typedef struct GetServerDirectory_Response
{
	eServiceError serviceError;	/*!< 对象类别<br>该值应始终指定为 1 (代表 logical-device)，不应指定为其他值。 */
	StringList* reference;		/*!< 逻辑设备引用列表 */
	Boolean moreFollows;		/*!< moreFollows。<br>
									值为 FALSE 代表当次请求已返回与指定参数对应的全部内容；<br>
									值为 TRUE 代表当次请求的响应数据之后还有内容没有返回。<br>
									如要获取后续内容，应根据档次返回的结果调整请求参数，并再次发起请求。<br>
									请求中可以指定 referenceAfter 参数的，通过 referenceAfter 参数的值来调整即可；<br>
									请求中不能指定 referenceAfter参数的，需要通过更换其他参数的值来调整。 */
}GetServerDirectory_Response;

/*!	\brief	ACSI 服务接口 GetLogicalDeviceDirectory 的请求数据 */
typedef struct GetLogicalDeviceDirectory_Request
{
	char* ldName;			/*!< 逻辑设备名称（LDName）。
								若模型文件中有给逻辑设备配置 LDName，则 LDName 为配置的名称(ldName)
								若模型文件中未给逻辑设备配置 LDName，则 LDName 是 "IED 名称(name) + 逻辑设备实例名称(inst) " */
	char* referenceAfter;	/*!< 这里是逻辑节点的引用（lnReference）
								用于请求指定的 lnReference 之后的信息。 */
}GetLogicalDeviceDirectory_Request;

/*!	\brief	ACSI 服务接口 GetLogicalDeviceDirectory 的响应数据	 */
typedef struct GetLogicalDeviceDirectory_Response
{
	eServiceError serviceError;	/*!< 逻辑设备下的逻辑节点引用列表。
									若模型文件中有给逻辑设备配置 LDName，则 LDName 为配置的名称(ldName)
									若模型文件中未给逻辑设备配置 LDName，则 LDName 是 "IED 名称(name) + 逻辑设备实例名称(inst) " */
	StringList* lnReference;	/*!< 逻辑节点LN引用集合 */
	Boolean moreFollows;		/*!< 分页标志
									值为 FALSE 代表当次请求已返回与指定参数对应的全部内容；
									值为 TRUE 代表当次请求的响应数据之后还有内容没有返回。
									如要获取后续内容，应根据档次返回的结果调整请求参数，并再次发起请求。
									请求中可以指定 referenceAfter 参数的，通过 referenceAfter 参数的值来调整即可；
									请求中不能指定 referenceAfter参数的，需要通过更换其他参数的值来调整。 */
}GetLogicalDeviceDirectory_Response;


/*! \brief 逻辑节点目录查询请求结构体 */
typedef struct GetLogicalNodeDirectory_Request
{
	char* reference;					/*!< 目标对象引用路径(如"LD1/GGIO1") */
	enum IEC61850_ACSIClass acsiClass;	/*!< ACSI服务类别(逻辑节点/逻辑设备等) */
	char* referenceAfter;				/*!< 分页查询起始位置(NULL表示从头查询) */
} GetLogicalNodeDirectory_Request;

/*! \brief 逻辑节点目录查询响应结构体 */
typedef struct GetLogicalNodeDirectory_Response
{
	eServiceError serviceError;	/*!< 服务错误码(0表示成功) */
	StringList* reference;		/*!< 逻辑节点引用链表(动态分配内存) */
	Boolean moreFollows;		/*!< 分页标志(TRUE表示还有后续数据) */
} GetLogicalNodeDirectory_Response;

/*! \brief 全数据查询请求结构体 */
typedef struct GetAllData_Request
{
	char* reference;		/*!< 目标对象引用路径 */
	char* fc;				/*!< 功能约束(Functional Constraint) */
	char* referenceAfter;	/*!< 分页查询起始位置 */
} GetAllData_Request;

/*! \brief 数据值查询响应结构体 */
typedef struct GetAllDataValues_Response
{
	eServiceError serviceError;			/*!< 服务错误码 */
	IEC61850_DataAttributeData data;	/*!< 数据属性值集合 */
	Boolean moreFollows;				/*!< 分页标志 */
} GetAllDataValues_Response;

/*! \brief 数据定义查询响应结构体 */
typedef struct GetAllDataDefinition_Response
{
	eServiceError serviceError;	/*!< 服务错误码 */
	DataDefinitions data;		/*!< 数据定义描述结构体 */
	Boolean moreFollows;		/*!< 分页标志 */
} GetAllDataDefinition_Response;

/*! \brief 控制块值查询请求结构体 */
typedef struct GetAllCBValues_Request
{
	char* reference;					/*!< 控制块引用路径(如"LD1/GGIO1.RP1") */
	enum IEC61850_ACSIClass acsiClass;	/*!< 控制块类型(报告/日志等) */
	char* referenceAfter;				/*!< 分页查询起始位置 */
} GetAllCBValues_Request;

/*! \brief 控制块值查询响应结构体 */
typedef struct GetAllCBValues_Response
{
	eServiceError serviceError;	/*!< 服务错误码 */
	GetAllCBValsReturn cbValue;	/*!< 控制块值返回结构体 */
	Boolean moreFollows;		/*!< 分页标志 */
} GetAllCBValues_Response;

/*!	\brief	数据属性值	 */
typedef struct FCDAVals
{
	char dataRef[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 数据引用 */
	char FC[3];										/*!< 功能约束 */
	IEC61850_DataAttributeData dataAttribute;		/*!< 数据值 */
} FCDAVals;

/*! \brief 数据集值设置请求结构体 */
typedef struct SetDataValues_Request
{
	U32 dataNum;		/*!< 数据数量 */
	FCDAVals* fcdaVals;	/*!< 内容为 struct #FCDAVals 的数组，元素数量由 length 成员指定 */
}SetDataValues_Request;

/*! \brief 数据集值设置响应结构体 */
typedef struct SetDataValues_Response
{
	eServiceError serviceError;	/*!< 响应的 ServiceError。
									肯定响应时，值为 SERVICE_ERROR_NO_ERROR (0) ；
									否定响应时，值为其他非 0 值的 eServiceError  */
	ServiceErrorList result;	/*!< 所有编辑的定值对应响应的 eServiceError 列表。
									用于接收每个请求编辑的定值所对应的相应结果  */
}SetDataValues_Response;

/*! \brief 数据目录查询请求结构体 */
typedef struct GetDataDirectory_Request
{
	char* dataReference;	/*!< 目标数据对象引用路径(格式：LDName/LNName.DOName) */
	char* referenceAfter;	/*!< 分页查询起始位置(NULL表示从首条记录开始查询) */
} GetDataDirectory_Request;

/*\brief 数据目录 */
typedef struct DataDirectory
{
	char ref[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 数据引用 */
	char FC[3];									/*!< 功能约束 */
} DataDirectory;

/*! \brief 数据目录查询响应结构体 */
typedef struct GetDataDirectory_Response
{
	eServiceError serviceError;	/*!< 服务错误码(0=成功) */
	U32 dataNum;				/*!< 数据数量 */
	DataDirectory* dataDirs;	/*!< 服务目录列表。内容为 struct #DataDirectory 的数组，元素数量由 dataNum 成员指定 */
	Boolean moreFollows;		/*!< 分页标志(TRUE表示还有后续数据) */
} GetDataDirectory_Response;

/*! \brief 数据定义查询请求结构体 */
typedef struct GetDataDefinition_Request
{
	char reference[OBJECT_REFERENCE_STRING_LEN + 1];	/*!< 完整对象引用路径 */
	char fc[FC_LEN + 1];								/*!< 功能约束代码(ST/MX等) */
} GetDataDefinition_Request;

/*! \brief 数据定义查询响应结构体 */
typedef struct GetDataDefinition_Response
{
	eServiceError serviceError;				/*!< 服务错误码 */
	DataRefDefinition* dataRefDefinition;	/*!< 数据定义结构体数组指针 */
} GetDataDefinition_Response;


#ifdef __cplusplus
}
#endif

#endif
